From ccaf4d120500affef1102cf3366696d397f2311e Mon Sep 17 00:00:00 2001 From: mofeng-git Date: Wed, 11 Feb 2026 20:55:20 +0800 Subject: [PATCH] =?UTF-8?q?fix(rtsp):=20=E4=BF=AE=E5=A4=8D=E6=B8=85?= =?UTF-8?q?=E7=A9=BA=E7=94=A8=E6=88=B7=E5=90=8D=E5=90=8E=E4=BB=8D=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E8=AE=A4=E8=AF=81=E5=AF=BC=E8=87=B4=20401=20=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rtsp/service.rs | 46 ++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/rtsp/service.rs b/src/rtsp/service.rs index f15ff4d4..ae17ab6d 100644 --- a/src/rtsp/service.rs +++ b/src/rtsp/service.rs @@ -246,15 +246,7 @@ async fn handle_client( shared: SharedRtspState, ) -> Result<()> { let cfg_snapshot = config.read().await.clone(); - - let auth_enabled = cfg_snapshot - .username - .as_ref() - .is_some_and(|u| !u.is_empty()) - || cfg_snapshot - .password - .as_ref() - .is_some_and(|p| !p.is_empty()); + let expected_auth = rtsp_auth_credentials(&cfg_snapshot); if cfg_snapshot.allow_one_client { let mut active_guard = shared.active_client.lock().await; @@ -301,11 +293,9 @@ async fn handle_client( continue; } - if auth_enabled { - let expected_user = cfg_snapshot.username.clone().unwrap_or_default(); - let expected_pass = cfg_snapshot.password.clone().unwrap_or_default(); + if let Some((expected_user, expected_pass)) = expected_auth.as_ref() { let ok = extract_basic_auth(&req) - .map(|(u, p)| u == expected_user && p == expected_pass) + .map(|(u, p)| u == expected_user.as_str() && p == expected_pass.as_str()) .unwrap_or(false); if !ok { send_response( @@ -747,6 +737,18 @@ fn extract_basic_auth(req: &RtspRequest) -> Option<(String, String)> { Some((user.to_string(), pass.to_string())) } +fn rtsp_auth_credentials(config: &RtspConfig) -> Option<(String, String)> { + let username = config.username.as_ref()?.trim(); + if username.is_empty() { + return None; + } + + Some(( + username.to_string(), + config.password.clone().unwrap_or_default(), + )) +} + fn parse_interleaved_channel(transport: &str) -> Option { let lower = transport.to_ascii_lowercase(); if let Some((_, v)) = lower.split_once("interleaved=") { @@ -1320,4 +1322,22 @@ mod tests { assert!(fmtp_value.contains("sprop-sps=")); assert!(fmtp_value.contains("sprop-pps=")); } + + #[test] + fn rtsp_auth_requires_non_empty_username() { + let mut config = RtspConfig::default(); + config.password = Some("secret".to_string()); + assert!(rtsp_auth_credentials(&config).is_none()); + + config.username = Some("".to_string()); + assert!(rtsp_auth_credentials(&config).is_none()); + + config.username = Some("user".to_string()); + let credentials = rtsp_auth_credentials(&config).expect("expected credentials"); + assert_eq!(credentials, ("user".to_string(), "secret".to_string())); + + config.password = None; + let credentials = rtsp_auth_credentials(&config).expect("expected credentials"); + assert_eq!(credentials, ("user".to_string(), "".to_string())); + } }