From 82a0d6b0abee73432d30b33ebcc2358afd0904eb Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sun, 18 Jan 2026 16:11:59 +0000 Subject: [PATCH] fix: more reliable parsing of `dclogin:` links with ip address as host (#7734) Also adds a test for it. closes #7733 --- src/qr/dclogin_scheme.rs | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/qr/dclogin_scheme.rs b/src/qr/dclogin_scheme.rs index cd4352498..4059ee0ab 100644 --- a/src/qr/dclogin_scheme.rs +++ b/src/qr/dclogin_scheme.rs @@ -59,14 +59,12 @@ pub enum LoginOptions { /// scheme: `dclogin://user@host/?p=password&v=1[&options]` /// read more about the scheme at pub(super) fn decode_login(qr: &str) -> Result { - let url = url::Url::parse(qr).with_context(|| format!("Malformed url: {qr:?}"))?; + let qr = qr.replacen("://", ":", 1); - let url_without_scheme = qr + let url = url::Url::parse(&qr).with_context(|| format!("Malformed url: {qr:?}"))?; + let payload = qr .get(DCLOGIN_SCHEME.len()..) .context("invalid DCLOGIN payload E1")?; - let payload = url_without_scheme - .strip_prefix("//") - .unwrap_or(url_without_scheme); let addr = payload .split(['?', '/']) @@ -365,4 +363,32 @@ mod test { } Ok(()) } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_decode_dclogin_ipv4() -> anyhow::Result<()> { + let result = decode_login("dclogin://test@[127.0.0.1]?p=1234&v=1")?; + if let Qr::Login { address, options } = result { + assert_eq!(address, "test@[127.0.0.1]".to_owned()); + assert_eq!(options, login_options_just_pw!("1234".to_owned())); + } else { + unreachable!("wrong type"); + } + Ok(()) + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_decode_dclogin_ipv6() -> anyhow::Result<()> { + let result = + decode_login("dclogin://test@[2001:0db8:85a3:0000:0000:8a2e:0370:7334]?p=1234&v=1")?; + if let Qr::Login { address, options } = result { + assert_eq!( + address, + "test@[2001:0db8:85a3:0000:0000:8a2e:0370:7334]".to_owned() + ); + assert_eq!(options, login_options_just_pw!("1234".to_owned())); + } else { + unreachable!("wrong type"); + } + Ok(()) + } }