@@ -770,7 +770,7 @@ impl Conn {
770770 if auth_denied {
771771 return ;
772772 }
773- let track_codec = Some ( fourcc_auth_label ( & track. fourcc ) ) ;
773+ let track_codec = media_fourcc_auth_label ( & track. fourcc ) ;
774774 if !self . media_allowed ( frame_type, track_codec. as_deref ( ) ) {
775775 auth_denied = true ;
776776 }
@@ -2283,6 +2283,22 @@ fn read_data_event_name(buf: &mut Buffer, is_string: bool, out: &mut [u8; 64]) -
22832283 }
22842284}
22852285
2286+ /// Wildcard FourCC (`*`) is valid in E-RTMP capability objects but must not
2287+ /// appear on publisher media tags — it carries no concrete codec identity and
2288+ /// would let codec-specific `on_media_cb` deny lists be bypassed.
2289+ fn is_wildcard_media_fourcc ( fourcc : & [ u8 ; 4 ] ) -> bool {
2290+ fourcc[ 0 ] == b'*'
2291+ }
2292+
2293+ /// Codec label for `on_media_cb`, or `None` when the wire FourCC cannot be
2294+ /// authorized (wildcard / unknown-enhanced identity).
2295+ fn media_fourcc_auth_label ( fourcc : & [ u8 ; 4 ] ) -> Option < String > {
2296+ if is_wildcard_media_fourcc ( fourcc) {
2297+ return None ;
2298+ }
2299+ Some ( fourcc_auth_label ( fourcc) )
2300+ }
2301+
22862302/// Stable codec label for `on_media_cb` authorization. Valid UTF-8 FourCCs are
22872303/// passed through; non-UTF-8 bytes are hex-encoded so deny-list policies can
22882304/// still observe the identity instead of receiving `None`.
@@ -2298,7 +2314,7 @@ fn fourcc_auth_label(fourcc: &[u8; 4]) -> String {
22982314
22992315fn detect_video_codec ( payload : & [ u8 ] ) -> Option < String > {
23002316 if let Some ( cc) = first_track_fourcc ( FrameType :: Video , payload) {
2301- return Some ( fourcc_auth_label ( & cc) ) ;
2317+ return media_fourcc_auth_label ( & cc) ;
23022318 }
23032319 let mut hdr = VideoHeader :: default ( ) ;
23042320 if crate :: ertmp:: exvideo:: exvideo_parse ( payload, & mut hdr) . is_err ( ) {
@@ -2307,7 +2323,7 @@ fn detect_video_codec(payload: &[u8]) -> Option<String> {
23072323 if hdr. is_ex_header != 0 {
23082324 let mut fourcc = [ 0u8 ; 4 ] ;
23092325 fourcc. copy_from_slice ( & hdr. fourcc [ ..4 ] ) ;
2310- Some ( fourcc_auth_label ( & fourcc) )
2326+ return media_fourcc_auth_label ( & fourcc) ;
23112327 } else {
23122328 match payload[ 0 ] & 0x0F {
23132329 7 => Some ( "avc1" . to_string ( ) ) ,
@@ -2320,7 +2336,7 @@ fn detect_video_codec(payload: &[u8]) -> Option<String> {
23202336
23212337fn detect_audio_codec ( payload : & [ u8 ] ) -> Option < String > {
23222338 if let Some ( cc) = first_track_fourcc ( FrameType :: Audio , payload) {
2323- return Some ( fourcc_auth_label ( & cc) ) ;
2339+ return media_fourcc_auth_label ( & cc) ;
23242340 }
23252341 let mut hdr = AudioHeader :: default ( ) ;
23262342 if crate :: ertmp:: exaudio:: exaudio_parse ( payload, & mut hdr) . is_err ( ) {
@@ -2329,7 +2345,7 @@ fn detect_audio_codec(payload: &[u8]) -> Option<String> {
23292345 if hdr. is_ex_header != 0 {
23302346 let mut fourcc = [ 0u8 ; 4 ] ;
23312347 fourcc. copy_from_slice ( & hdr. fourcc [ ..4 ] ) ;
2332- Some ( fourcc_auth_label ( & fourcc) )
2348+ return media_fourcc_auth_label ( & fourcc) ;
23332349 } else {
23342350 match hdr. audio_codec {
23352351 AudioCodec :: Aac => Some ( "mp4a" . to_string ( ) ) ,
@@ -3751,6 +3767,36 @@ mod tests {
37513767 assert ! ( conn. pending_relay. is_empty( ) ) ;
37523768 }
37533769
3770+ #[ test]
3771+ fn on_media_cb_deny_list_blocks_wildcard_enhanced_fourcc ( ) {
3772+ fn deny_hevc_and_av1 ( _: u64 , frame_type : FrameType , codec : Option < & str > ) -> bool {
3773+ if frame_type == FrameType :: Video {
3774+ return !matches ! ( codec, Some ( "hvc1" ) | Some ( "av01" ) ) ;
3775+ }
3776+ true
3777+ }
3778+
3779+ let mut conn = Conn :: new ( ) ;
3780+ conn. relay_enabled = true ;
3781+ conn. current_stream = Some ( Box :: new ( Stream :: new ( 1 ) ) ) ;
3782+ conn. current_stream . as_mut ( ) . unwrap ( ) . is_publishing = true ;
3783+ conn. on_media_cb = Some ( deny_hevc_and_av1) ;
3784+
3785+ let hvc1 = vec ! [ 0x90 , b'h' , b'v' , b'c' , b'1' , 0 , 0 , 0 , 1 , 0xAA ] ;
3786+ assert_eq ! (
3787+ conn. handle_media_frame( 1 , FrameType :: Video , 0 , & hvc1) ,
3788+ Err ( ErrorCode :: Auth )
3789+ ) ;
3790+
3791+ let wildcard = vec ! [ 0x90 , b'*' , b' ' , b' ' , b' ' , 0 , 0 , 0 , 1 , 0xAA ] ;
3792+ assert_eq ! (
3793+ conn. handle_media_frame( 1 , FrameType :: Video , 0 , & wildcard) ,
3794+ Err ( ErrorCode :: Auth ) ,
3795+ "wildcard media FourCC must not bypass codec-specific deny lists"
3796+ ) ;
3797+ assert ! ( conn. pending_relay. is_empty( ) ) ;
3798+ }
3799+
37543800 #[ test]
37553801 fn evict_active_publish_route_clears_detected_codecs ( ) {
37563802 let mut conn = Conn :: new ( ) ;
0 commit comments