diff --git a/internal/auth/manager_test.go b/internal/auth/manager_test.go index 160db708..72d24db0 100644 --- a/internal/auth/manager_test.go +++ b/internal/auth/manager_test.go @@ -16,15 +16,15 @@ import ( "github.com/stretchr/testify/require" ) -func mustParseCIDR(v string) net.IPNet { +func mustParseCIDR(v string) conf.IPNetwork { _, ne, err := net.ParseCIDR(v) if err != nil { panic(err) } if ipv4 := ne.IP.To4(); ipv4 != nil { - return net.IPNet{IP: ipv4, Mask: ne.Mask[len(ne.Mask)-4 : len(ne.Mask)]} + return conf.IPNetwork{IP: ipv4, Mask: ne.Mask[len(ne.Mask)-4 : len(ne.Mask)]} } - return *ne + return conf.IPNetwork(*ne) } func TestAuthInternal(t *testing.T) { diff --git a/internal/conf/auth_action.go b/internal/conf/auth_action.go index 87906ce2..0d598915 100644 --- a/internal/conf/auth_action.go +++ b/internal/conf/auth_action.go @@ -1,7 +1,6 @@ package conf import ( - "encoding/json" "fmt" "github.com/bluenviron/mediamtx/internal/conf/jsonwrapper" @@ -20,11 +19,6 @@ const ( AuthActionPprof AuthAction = "pprof" ) -// MarshalJSON implements json.Marshaler. -func (d AuthAction) MarshalJSON() ([]byte, error) { - return json.Marshal(string(d)) -} - // UnmarshalJSON implements json.Unmarshaler. func (d *AuthAction) UnmarshalJSON(b []byte) error { var in string diff --git a/internal/conf/auth_internal_user.go b/internal/conf/auth_internal_user.go new file mode 100644 index 00000000..a09dcc0a --- /dev/null +++ b/internal/conf/auth_internal_user.go @@ -0,0 +1,9 @@ +package conf + +// AuthInternalUser is an user. +type AuthInternalUser struct { + User Credential `json:"user"` + Pass Credential `json:"pass"` + IPs IPNetworks `json:"ips"` + Permissions []AuthInternalUserPermission `json:"permissions"` +} diff --git a/internal/conf/auth_internal_user_permission.go b/internal/conf/auth_internal_user_permission.go new file mode 100644 index 00000000..13e2c5a4 --- /dev/null +++ b/internal/conf/auth_internal_user_permission.go @@ -0,0 +1,7 @@ +package conf + +// AuthInternalUserPermission is a permission of a user. +type AuthInternalUserPermission struct { + Action AuthAction `json:"action"` + Path string `json:"path"` +} diff --git a/internal/conf/auth_internal_users.go b/internal/conf/auth_internal_users.go deleted file mode 100644 index b512132b..00000000 --- a/internal/conf/auth_internal_users.go +++ /dev/null @@ -1,21 +0,0 @@ -package conf - -// AuthInternalUserPermission is a permission of a user. -type AuthInternalUserPermission struct { - Action AuthAction `json:"action"` - Path string `json:"path"` -} - -// AuthInternalUser is an user. -type AuthInternalUser struct { - User Credential `json:"user"` - Pass Credential `json:"pass"` - IPs IPNetworks `json:"ips"` - Permissions []AuthInternalUserPermission `json:"permissions"` -} - -// AuthInternalUsers is a list of AuthInternalUser. -type AuthInternalUsers []AuthInternalUser - -// AuthInternalUserPermissions is a list of AuthInternalUserPermission. -type AuthInternalUserPermissions []AuthInternalUserPermission diff --git a/internal/conf/conf.go b/internal/conf/conf.go index 6d5f14cd..78a9690a 100644 --- a/internal/conf/conf.go +++ b/internal/conf/conf.go @@ -59,6 +59,13 @@ func setAllNilSlicesToEmptyRecursive(rv reflect.Value) { case reflect.Slice: if field.IsNil() { field.Set(reflect.MakeSlice(field.Type(), 0, 0)) + } else { + for j := range field.Len() { + elem := field.Index(j) + if elem.Kind() == reflect.Pointer || elem.Kind() == reflect.Struct { + setAllNilSlicesToEmptyRecursive(elem) + } + } } case reflect.Pointer: @@ -110,15 +117,15 @@ func copyStructFields(dest any, source any) { } } -func mustParseCIDR(v string) net.IPNet { +func mustParseCIDR(v string) IPNetwork { _, ne, err := net.ParseCIDR(v) if err != nil { panic(err) } if ipv4 := ne.IP.To4(); ipv4 != nil { - return net.IPNet{IP: ipv4, Mask: ne.Mask[len(ne.Mask)-4 : len(ne.Mask)]} + return IPNetwork{IP: ipv4, Mask: ne.Mask[len(ne.Mask)-4 : len(ne.Mask)]} } - return *ne + return IPNetwork(*ne) } func anyPathHasDeprecatedCredentials(pathDefaults Path, paths map[string]*OptionalPath) bool { @@ -198,7 +205,7 @@ type nilLogger struct{} func (nilLogger) Log(_ logger.Level, _ string, _ ...any) { } -var defaultAuthInternalUsers = AuthInternalUsers{ +var defaultAuthInternalUsers = []AuthInternalUser{ { User: "any", Pass: "", @@ -251,16 +258,16 @@ type Conf struct { RunOnDisconnect string `json:"runOnDisconnect"` // Authentication - AuthMethod AuthMethod `json:"authMethod"` - AuthInternalUsers AuthInternalUsers `json:"authInternalUsers"` - AuthHTTPAddress string `json:"authHTTPAddress"` - ExternalAuthenticationURL *string `json:"externalAuthenticationURL,omitempty"` // deprecated - AuthHTTPExclude AuthInternalUserPermissions `json:"authHTTPExclude"` - AuthJWTJWKS string `json:"authJWTJWKS"` - AuthJWTJWKSFingerprint string `json:"authJWTJWKSFingerprint"` - AuthJWTClaimKey string `json:"authJWTClaimKey"` - AuthJWTExclude AuthInternalUserPermissions `json:"authJWTExclude"` - AuthJWTInHTTPQuery bool `json:"authJWTInHTTPQuery"` + AuthMethod AuthMethod `json:"authMethod"` + AuthInternalUsers []AuthInternalUser `json:"authInternalUsers"` + AuthHTTPAddress string `json:"authHTTPAddress"` + ExternalAuthenticationURL *string `json:"externalAuthenticationURL,omitempty"` // deprecated + AuthHTTPExclude []AuthInternalUserPermission `json:"authHTTPExclude"` + AuthJWTJWKS string `json:"authJWTJWKS"` + AuthJWTJWKSFingerprint string `json:"authJWTJWKSFingerprint"` + AuthJWTClaimKey string `json:"authJWTClaimKey"` + AuthJWTExclude []AuthInternalUserPermission `json:"authJWTExclude"` + AuthJWTInHTTPQuery bool `json:"authJWTInHTTPQuery"` // Control API API bool `json:"api"` @@ -357,28 +364,28 @@ type Conf struct { HLSMuxerCloseAfter Duration `json:"hlsMuxerCloseAfter"` // WebRTC server - WebRTC bool `json:"webrtc"` - WebRTCDisable *bool `json:"webrtcDisable,omitempty"` // deprecated - WebRTCAddress string `json:"webrtcAddress"` - WebRTCEncryption bool `json:"webrtcEncryption"` - WebRTCServerKey string `json:"webrtcServerKey"` - WebRTCServerCert string `json:"webrtcServerCert"` - WebRTCAllowOrigin *string `json:"webrtcAllowOrigin,omitempty"` // deprecated - WebRTCAllowOrigins []string `json:"webrtcAllowOrigins"` - WebRTCTrustedProxies IPNetworks `json:"webrtcTrustedProxies"` - WebRTCLocalUDPAddress string `json:"webrtcLocalUDPAddress"` - WebRTCLocalTCPAddress string `json:"webrtcLocalTCPAddress"` - WebRTCIPsFromInterfaces bool `json:"webrtcIPsFromInterfaces"` - WebRTCIPsFromInterfacesList []string `json:"webrtcIPsFromInterfacesList"` - WebRTCAdditionalHosts []string `json:"webrtcAdditionalHosts"` - WebRTCICEServers2 WebRTCICEServers `json:"webrtcICEServers2"` - WebRTCHandshakeTimeout Duration `json:"webrtcHandshakeTimeout"` - WebRTCTrackGatherTimeout Duration `json:"webrtcTrackGatherTimeout"` - WebRTCSTUNGatherTimeout Duration `json:"webrtcSTUNGatherTimeout"` - WebRTCICEUDPMuxAddress *string `json:"webrtcICEUDPMuxAddress,omitempty"` // deprecated - WebRTCICETCPMuxAddress *string `json:"webrtcICETCPMuxAddress,omitempty"` // deprecated - WebRTCICEHostNAT1To1IPs *[]string `json:"webrtcICEHostNAT1To1IPs,omitempty"` // deprecated - WebRTCICEServers *[]string `json:"webrtcICEServers,omitempty"` // deprecated + WebRTC bool `json:"webrtc"` + WebRTCDisable *bool `json:"webrtcDisable,omitempty"` // deprecated + WebRTCAddress string `json:"webrtcAddress"` + WebRTCEncryption bool `json:"webrtcEncryption"` + WebRTCServerKey string `json:"webrtcServerKey"` + WebRTCServerCert string `json:"webrtcServerCert"` + WebRTCAllowOrigin *string `json:"webrtcAllowOrigin,omitempty"` // deprecated + WebRTCAllowOrigins []string `json:"webrtcAllowOrigins"` + WebRTCTrustedProxies IPNetworks `json:"webrtcTrustedProxies"` + WebRTCLocalUDPAddress string `json:"webrtcLocalUDPAddress"` + WebRTCLocalTCPAddress string `json:"webrtcLocalTCPAddress"` + WebRTCIPsFromInterfaces bool `json:"webrtcIPsFromInterfaces"` + WebRTCIPsFromInterfacesList []string `json:"webrtcIPsFromInterfacesList"` + WebRTCAdditionalHosts []string `json:"webrtcAdditionalHosts"` + WebRTCICEServers2 []WebRTCICEServer `json:"webrtcICEServers2"` + WebRTCHandshakeTimeout Duration `json:"webrtcHandshakeTimeout"` + WebRTCTrackGatherTimeout Duration `json:"webrtcTrackGatherTimeout"` + WebRTCSTUNGatherTimeout Duration `json:"webrtcSTUNGatherTimeout"` + WebRTCICEUDPMuxAddress *string `json:"webrtcICEUDPMuxAddress,omitempty"` // deprecated + WebRTCICETCPMuxAddress *string `json:"webrtcICETCPMuxAddress,omitempty"` // deprecated + WebRTCICEHostNAT1To1IPs *[]string `json:"webrtcICEHostNAT1To1IPs,omitempty"` // deprecated + WebRTCICEServers *[]string `json:"webrtcICEServers,omitempty"` // deprecated // SRT server SRT bool `json:"srt"` @@ -403,7 +410,7 @@ type Conf struct { func (conf *Conf) setDefaults() { // General conf.LogLevel = LogLevel(logger.Info) - conf.LogDestinations = LogDestinations{logger.DestinationStdout} + conf.LogDestinations = LogDestinations{LogDestination(logger.DestinationStdout)} conf.LogStructured = false conf.LogFile = "mediamtx.log" conf.SysLogPrefix = "mediamtx" @@ -472,7 +479,7 @@ func (conf *Conf) setDefaults() { conf.MulticastSRTCPPort = 8007 conf.RTSPServerKey = "server.key" conf.RTSPServerCert = "server.crt" - conf.RTSPAuthMethods = RTSPAuthMethods{auth.VerifyMethodBasic} + conf.RTSPAuthMethods = RTSPAuthMethods{RTSPAuthMethod(auth.VerifyMethodBasic)} // RTMP server conf.RTMP = true @@ -871,7 +878,7 @@ func (conf *Conf) Validate(l logger.Writer) error { return fmt.Errorf("at least one 'rtspAuthMethods' must be provided") } - if slices.Contains(conf.RTSPAuthMethods, auth.VerifyMethodDigestMD5) { + if slices.Contains(conf.RTSPAuthMethods, RTSPAuthMethod(auth.VerifyMethodDigestMD5)) { if conf.AuthMethod != AuthMethodInternal { return fmt.Errorf("when RTSP digest is enabled, the only supported auth method is 'internal'") } diff --git a/internal/conf/conf_test.go b/internal/conf/conf_test.go index ce17e23b..67160ae8 100644 --- a/internal/conf/conf_test.go +++ b/internal/conf/conf_test.go @@ -209,7 +209,7 @@ func TestConfDeprecatedAuth(t *testing.T) { conf, _, err := Load(tmpf, nil, nil) require.NoError(t, err) - require.Equal(t, AuthInternalUsers{ + require.Equal(t, []AuthInternalUser{ { User: "any", Permissions: []AuthInternalUserPermission{ diff --git a/internal/conf/credential.go b/internal/conf/credential.go index 3a417228..94f704c5 100644 --- a/internal/conf/credential.go +++ b/internal/conf/credential.go @@ -3,7 +3,6 @@ package conf import ( "crypto/sha256" "encoding/base64" - "encoding/json" "fmt" "regexp" "strings" @@ -28,11 +27,6 @@ func sha256Base64(in string) string { // Credential is a parameter that is used as username or password. type Credential string -// MarshalJSON implements json.Marshaler. -func (d Credential) MarshalJSON() ([]byte, error) { - return json.Marshal(string(d)) -} - // UnmarshalJSON implements json.Unmarshaler. func (d *Credential) UnmarshalJSON(b []byte) error { var in string diff --git a/internal/conf/credential_test.go b/internal/conf/credential_test.go index 4c622aaa..072b8427 100644 --- a/internal/conf/credential_test.go +++ b/internal/conf/credential_test.go @@ -7,14 +7,6 @@ import ( ) func TestCredential(t *testing.T) { - t.Run("MarshalJSON", func(t *testing.T) { - cred := Credential("password") - expectedJSON := []byte(`"password"`) - actualJSON, err := cred.MarshalJSON() - assert.NoError(t, err) - assert.Equal(t, expectedJSON, actualJSON) - }) - t.Run("UnmarshalJSON", func(t *testing.T) { expectedCred := Credential("password") jsonData := []byte(`"password"`) diff --git a/internal/conf/ip_network.go b/internal/conf/ip_network.go new file mode 100644 index 00000000..0a579acd --- /dev/null +++ b/internal/conf/ip_network.go @@ -0,0 +1,55 @@ +package conf + +import ( + "encoding/json" + "fmt" + "net" + + "github.com/bluenviron/mediamtx/internal/conf/jsonwrapper" +) + +// IPNetwork represents an IP network. +type IPNetwork net.IPNet + +// MarshalJSON implements json.Marshaler. +func (n IPNetwork) MarshalJSON() ([]byte, error) { + return json.Marshal(n.String()) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (n *IPNetwork) UnmarshalJSON(b []byte) error { + var t string + if err := jsonwrapper.Unmarshal(b, &t); err != nil { + return err + } + + if _, ipnet, err := net.ParseCIDR(t); err == nil { + if ipv4 := ipnet.IP.To4(); ipv4 != nil { + *n = IPNetwork{IP: ipv4, Mask: ipnet.Mask[len(ipnet.Mask)-4 : len(ipnet.Mask)]} + } else { + *n = IPNetwork(*ipnet) + } + } else if ip := net.ParseIP(t); ip != nil { + if ipv4 := ip.To4(); ipv4 != nil { + *n = IPNetwork{IP: ipv4, Mask: net.CIDRMask(32, 32)} + } else { + *n = IPNetwork{IP: ip, Mask: net.CIDRMask(128, 128)} + } + } else { + return fmt.Errorf("unable to parse IP/CIDR '%s'", t) + } + + return nil +} + +// String implements fmt.Stringer. +func (n IPNetwork) String() string { + ipnet := net.IPNet(n) + return ipnet.String() +} + +// Contains checks whether the IP is part of the network. +func (n IPNetwork) Contains(ip net.IP) bool { + ipnet := net.IPNet(n) + return ipnet.Contains(ip) +} diff --git a/internal/conf/ip_networks.go b/internal/conf/ip_networks.go index ea25d53f..796d7dd1 100644 --- a/internal/conf/ip_networks.go +++ b/internal/conf/ip_networks.go @@ -2,68 +2,19 @@ package conf import ( "encoding/json" - "fmt" "net" - "sort" "strings" "github.com/bluenviron/mediamtx/internal/conf/jsonwrapper" ) // IPNetworks is a parameter that contains a list of IP networks. -type IPNetworks []net.IPNet - -// MarshalJSON implements json.Marshaler. -func (d IPNetworks) MarshalJSON() ([]byte, error) { - out := make([]string, len(d)) - - for i, v := range d { - out[i] = v.String() - } - - sort.Strings(out) - - return json.Marshal(out) -} - -// UnmarshalJSON implements json.Unmarshaler. -func (d *IPNetworks) UnmarshalJSON(b []byte) error { - var in []string - if err := jsonwrapper.Unmarshal(b, &in); err != nil { - return err - } - - *d = nil - - if len(in) == 0 { - return nil - } - - for _, t := range in { - if _, ipnet, err := net.ParseCIDR(t); err == nil { - if ipv4 := ipnet.IP.To4(); ipv4 != nil { - *d = append(*d, net.IPNet{IP: ipv4, Mask: ipnet.Mask[len(ipnet.Mask)-4 : len(ipnet.Mask)]}) - } else { - *d = append(*d, *ipnet) - } - } else if ip := net.ParseIP(t); ip != nil { - if ipv4 := ip.To4(); ipv4 != nil { - *d = append(*d, net.IPNet{IP: ipv4, Mask: net.CIDRMask(32, 32)}) - } else { - *d = append(*d, net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)}) - } - } else { - return fmt.Errorf("unable to parse IP/CIDR '%s'", t) - } - } - - return nil -} +type IPNetworks []IPNetwork // UnmarshalEnv implements env.Unmarshaler. func (d *IPNetworks) UnmarshalEnv(_ string, v string) error { byts, _ := json.Marshal(strings.Split(v, ",")) - return d.UnmarshalJSON(byts) + return jsonwrapper.Unmarshal(byts, d) } // ToTrustedProxies converts IPNetworks into a string slice for SetTrustedProxies. diff --git a/internal/conf/log_destination.go b/internal/conf/log_destination.go index 27695676..a8cb2a80 100644 --- a/internal/conf/log_destination.go +++ b/internal/conf/log_destination.go @@ -3,83 +3,48 @@ package conf import ( "encoding/json" "fmt" - "slices" - "strings" "github.com/bluenviron/mediamtx/internal/conf/jsonwrapper" "github.com/bluenviron/mediamtx/internal/logger" ) -// LogDestinations is the logDestionations parameter. -type LogDestinations []logger.Destination +// LogDestination represents a log destination. +type LogDestination logger.Destination // MarshalJSON implements json.Marshaler. -func (d LogDestinations) MarshalJSON() ([]byte, error) { - out := make([]string, len(d)) - i := 0 +func (d LogDestination) MarshalJSON() ([]byte, error) { + switch d { + case LogDestination(logger.DestinationStdout): + return json.Marshal("stdout") - for _, p := range d { - var v string + case LogDestination(logger.DestinationFile): + return json.Marshal("file") - switch p { - case logger.DestinationStdout: - v = "stdout" - - case logger.DestinationFile: - v = "file" - - default: - v = "syslog" - } - - out[i] = v - i++ + default: + return json.Marshal("syslog") } - - return json.Marshal(out) -} - -func (d *LogDestinations) contains(v logger.Destination) bool { - return slices.Contains(*d, v) } // UnmarshalJSON implements json.Unmarshaler. -func (d *LogDestinations) UnmarshalJSON(b []byte) error { - var in []string +func (d *LogDestination) UnmarshalJSON(b []byte) error { + var in string if err := jsonwrapper.Unmarshal(b, &in); err != nil { return err } - *d = nil + switch in { + case "stdout": + *d = LogDestination(logger.DestinationStdout) - for _, dest := range in { - var v logger.Destination - switch dest { - case "stdout": - v = logger.DestinationStdout + case "file": + *d = LogDestination(logger.DestinationFile) - case "file": - v = logger.DestinationFile + case "syslog": + *d = LogDestination(logger.DestinationSyslog) - case "syslog": - v = logger.DestinationSyslog - - default: - return fmt.Errorf("invalid log destination: %s", dest) - } - - if d.contains(v) { - return fmt.Errorf("log destination set twice") - } - - *d = append(*d, v) + default: + return fmt.Errorf("invalid log destination: %s", in) } return nil } - -// UnmarshalEnv implements env.Unmarshaler. -func (d *LogDestinations) UnmarshalEnv(_ string, v string) error { - byts, _ := json.Marshal(strings.Split(v, ",")) - return d.UnmarshalJSON(byts) -} diff --git a/internal/conf/log_destinations.go b/internal/conf/log_destinations.go new file mode 100644 index 00000000..913efe76 --- /dev/null +++ b/internal/conf/log_destinations.go @@ -0,0 +1,27 @@ +package conf + +import ( + "encoding/json" + "strings" + + "github.com/bluenviron/mediamtx/internal/conf/jsonwrapper" + "github.com/bluenviron/mediamtx/internal/logger" +) + +// LogDestinations is the logDestionations parameter. +type LogDestinations []LogDestination + +// UnmarshalEnv implements env.Unmarshaler. +func (d *LogDestinations) UnmarshalEnv(_ string, v string) error { + byts, _ := json.Marshal(strings.Split(v, ",")) + return jsonwrapper.Unmarshal(byts, d) +} + +// ToDestinations converts to logger.Destination slice. +func (d LogDestinations) ToDestinations() []logger.Destination { + out := make([]logger.Destination, len(d)) + for i, v := range d { + out[i] = logger.Destination(v) + } + return out +} diff --git a/internal/conf/rtsp_auth_method.go b/internal/conf/rtsp_auth_method.go new file mode 100644 index 00000000..d7915b8b --- /dev/null +++ b/internal/conf/rtsp_auth_method.go @@ -0,0 +1,44 @@ +package conf + +import ( + "encoding/json" + "fmt" + + "github.com/bluenviron/gortsplib/v5/pkg/auth" + "github.com/bluenviron/mediamtx/internal/conf/jsonwrapper" +) + +// RTSPAuthMethod represents an RTSP authentication method. +type RTSPAuthMethod auth.VerifyMethod + +// MarshalJSON implements json.Marshaler. +func (d RTSPAuthMethod) MarshalJSON() ([]byte, error) { + switch d { + case RTSPAuthMethod(auth.VerifyMethodBasic): + return json.Marshal("basic") + + default: + return json.Marshal("digest") + } +} + +// UnmarshalJSON implements json.Unmarshaler. +func (d *RTSPAuthMethod) UnmarshalJSON(b []byte) error { + var in string + if err := jsonwrapper.Unmarshal(b, &in); err != nil { + return err + } + + switch in { + case "basic": + *d = RTSPAuthMethod(auth.VerifyMethodBasic) + + case "digest": + *d = RTSPAuthMethod(auth.VerifyMethodDigestMD5) + + default: + return fmt.Errorf("invalid authentication method: '%s'", in) + } + + return nil +} diff --git a/internal/conf/rtsp_auth_methods.go b/internal/conf/rtsp_auth_methods.go index 06587dbe..1052961c 100644 --- a/internal/conf/rtsp_auth_methods.go +++ b/internal/conf/rtsp_auth_methods.go @@ -2,8 +2,6 @@ package conf import ( "encoding/json" - "fmt" - "sort" "strings" "github.com/bluenviron/gortsplib/v5/pkg/auth" @@ -11,54 +9,19 @@ import ( ) // RTSPAuthMethods is the rtspAuthMethods parameter. -type RTSPAuthMethods []auth.VerifyMethod - -// MarshalJSON implements json.Marshaler. -func (d RTSPAuthMethods) MarshalJSON() ([]byte, error) { - out := make([]string, len(d)) - - for i, v := range d { - switch v { - case auth.VerifyMethodBasic: - out[i] = "basic" - - default: - out[i] = "digest" - } - } - - sort.Strings(out) - - return json.Marshal(out) -} - -// UnmarshalJSON implements json.Unmarshaler. -func (d *RTSPAuthMethods) UnmarshalJSON(b []byte) error { - var in []string - if err := jsonwrapper.Unmarshal(b, &in); err != nil { - return err - } - - *d = nil - - for _, v := range in { - switch v { - case "basic": - *d = append(*d, auth.VerifyMethodBasic) - - case "digest": - *d = append(*d, auth.VerifyMethodDigestMD5) - - default: - return fmt.Errorf("invalid authentication method: '%s'", v) - } - } - - return nil -} +type RTSPAuthMethods []RTSPAuthMethod // UnmarshalEnv implements env.Unmarshaler. func (d *RTSPAuthMethods) UnmarshalEnv(_ string, v string) error { byts, _ := json.Marshal(strings.Split(v, ",")) - return d.UnmarshalJSON(byts) + return jsonwrapper.Unmarshal(byts, d) +} + +// ToAuthMethods converts to auth.VerifyMethod slice. +func (d RTSPAuthMethods) ToAuthMethods() []auth.VerifyMethod { + out := make([]auth.VerifyMethod, len(d)) + for i, v := range d { + out[i] = auth.VerifyMethod(v) + } + return out } diff --git a/internal/conf/webrtc_ice_server.go b/internal/conf/webrtc_ice_server.go index 64424ef3..a1258f6e 100644 --- a/internal/conf/webrtc_ice_server.go +++ b/internal/conf/webrtc_ice_server.go @@ -7,6 +7,3 @@ type WebRTCICEServer struct { Password string `json:"password"` ClientOnly bool `json:"clientOnly"` } - -// WebRTCICEServers is a list of WebRTCICEServer. -type WebRTCICEServers []WebRTCICEServer diff --git a/internal/core/core.go b/internal/core/core.go index 19956949..9f70b224 100644 --- a/internal/core/core.go +++ b/internal/core/core.go @@ -292,7 +292,7 @@ func (p *Core) createResources(initial bool) error { if p.logger == nil { i := &logger.Logger{ Level: logger.Level(p.conf.LogLevel), - Destinations: p.conf.LogDestinations, + Destinations: p.conf.LogDestinations.ToDestinations(), Structured: p.conf.LogStructured, File: p.conf.LogFile, SysLogPrefix: p.conf.SysLogPrefix, @@ -451,7 +451,7 @@ func (p *Core) createResources(initial bool) error { i := &rtsp.Server{ Address: p.conf.RTSPAddress, - AuthMethods: p.conf.RTSPAuthMethods, + AuthMethods: p.conf.RTSPAuthMethods.ToAuthMethods(), UDPReadBufferSize: udpReadBufferSize, ReadTimeout: p.conf.ReadTimeout, WriteTimeout: p.conf.WriteTimeout, @@ -493,7 +493,7 @@ func (p *Core) createResources(initial bool) error { i := &rtsp.Server{ Address: p.conf.RTSPSAddress, - AuthMethods: p.conf.RTSPAuthMethods, + AuthMethods: p.conf.RTSPAuthMethods.ToAuthMethods(), UDPReadBufferSize: udpReadBufferSize, ReadTimeout: p.conf.ReadTimeout, WriteTimeout: p.conf.WriteTimeout, diff --git a/internal/testapidocs/apidocs_test.go b/internal/testapidocs/apidocs_test.go index bca26a13..f7743024 100644 --- a/internal/testapidocs/apidocs_test.go +++ b/internal/testapidocs/apidocs_test.go @@ -1,17 +1,14 @@ package main import ( - "net" "os" "reflect" "strings" "testing" "time" - "github.com/bluenviron/gortsplib/v5/pkg/auth" "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/defs" - "github.com/bluenviron/mediamtx/internal/logger" "github.com/google/uuid" "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" @@ -73,7 +70,7 @@ func fillProperty(t *testing.T, rt reflect.Type, existing openAPIProperty) openA case rt == reflect.TypeOf(time.Time{}) || rt == reflect.TypeOf(conf.Duration(0)) || - rt == reflect.TypeOf(net.IPNet{}) || + rt == reflect.TypeOf(conf.IPNetwork{}) || rt == reflect.TypeOf(conf.Credential("")) || rt == reflect.TypeOf(conf.RecordFormat(0)) || rt == reflect.TypeOf(conf.AuthAction("")) || @@ -83,8 +80,8 @@ func fillProperty(t *testing.T, rt reflect.Type, existing openAPIProperty) openA rt == reflect.TypeOf(conf.RTSPRangeType(0)) || rt == reflect.TypeOf(conf.LogLevel(0)) || rt == reflect.TypeOf(conf.AuthMethod(0)) || - rt == reflect.TypeOf(logger.Destination(0)) || - rt == reflect.TypeOf(auth.VerifyMethod(0)) || + rt == reflect.TypeOf(conf.LogDestination(0)) || + rt == reflect.TypeOf(conf.RTSPAuthMethod(0)) || rt == reflect.TypeOf(conf.HLSVariant(0)) || rt == reflect.TypeOf(defs.APIRTMPConnState("")) || rt == reflect.TypeOf(defs.APIWebRTCSessionState("")) ||