diff --git a/nmrs/src/core/vpn.rs b/nmrs/src/core/vpn.rs index 85ba0d87..4616216d 100644 --- a/nmrs/src/core/vpn.rs +++ b/nmrs/src/core/vpn.rs @@ -723,7 +723,7 @@ pub(crate) async fn get_vpn_info(conn: &Connection, name: &str) -> Result settings_map @@ -742,12 +742,7 @@ pub(crate) async fn get_vpn_info(conn: &Connection, name: &str) -> Result { - // FIXME : vpn.data is a Dict in NM, not a plain string. - // Need to deserialize as HashMap and look up "remote". - // Cannot test without a real NM OpenVPN profile. - None - } + VpnType::OpenVpn => extract_openvpn_gateway(&settings_map), }; // IPv4 config @@ -840,3 +835,70 @@ pub(crate) async fn get_vpn_info(conn: &Connection, name: &str) -> Result>>, +) -> Option { + let zvariant::Value::Dict(dict) = settings_map.get("vpn")?.get("data")? else { + return None; + }; + dict.iter().find_map(|(k, v)| match (k, v) { + (zvariant::Value::Str(k), zvariant::Value::Str(v)) if k.as_str() == "remote" => { + Some(v.to_string()) + } + _ => None, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashMap; + + fn openvpn_settings_with_data( + data: HashMap, + ) -> HashMap>> { + let dict = zvariant::Dict::from(data); + let vpn_sec = HashMap::from([("data".to_string(), zvariant::Value::Dict(dict))]); + HashMap::from([("vpn".to_string(), vpn_sec)]) + } + + #[test] + fn openvpn_gateway_extracted_from_vpn_data() { + let data = HashMap::from([("remote".to_string(), "vpn.example.com:1194".to_string())]); + let settings = openvpn_settings_with_data(data); + assert_eq!( + extract_openvpn_gateway(&settings), + Some("vpn.example.com:1194".to_string()) + ); + } + + #[test] + fn openvpn_gateway_none_when_remote_key_absent() { + let data = HashMap::from([("dev".to_string(), "tun".to_string())]); + let settings = openvpn_settings_with_data(data); + assert_eq!(extract_openvpn_gateway(&settings), None); + } + + #[test] + fn openvpn_gateway_none_when_vpn_section_absent() { + let settings: HashMap>> = + HashMap::from([("connection".to_string(), HashMap::new())]); + assert_eq!(extract_openvpn_gateway(&settings), None); + } + + #[test] + fn openvpn_gateway_none_when_data_key_absent() { + let vpn_sec = HashMap::from([( + "service-type".to_string(), + zvariant::Value::Str("org.freedesktop.NetworkManager.openvpn".into()), + )]); + let settings = HashMap::from([("vpn".to_string(), vpn_sec)]); + assert_eq!(extract_openvpn_gateway(&settings), None); + } +}