use log::debug;
use std::collections::HashMap;
use zbus::Connection;
use zvariant::{OwnedObjectPath, Value};
use crate::Result;
use crate::api::models::ConnectionError;
use crate::util::utils::{connection_settings_proxy, settings_proxy};
use crate::util::validation::validate_connection_name;
pub(crate) async fn get_saved_connection_path(
conn: &Connection,
name: &str,
) -> Result<Option<OwnedObjectPath>> {
if should_skip_lookup(name)? {
return Ok(None);
}
let settings = settings_proxy(conn).await?;
let reply = settings
.call_method("ListConnections", &())
.await
.map_err(|e| ConnectionError::DbusOperation {
context: "failed to list saved connections".to_string(),
source: e,
})?;
let conns: Vec<OwnedObjectPath> = reply.body().deserialize()?;
for cpath in conns {
let cproxy = connection_settings_proxy(conn, cpath.clone()).await?;
let msg = cproxy.call_method("GetSettings", &()).await.map_err(|e| {
ConnectionError::DbusOperation {
context: format!("failed to get settings for {}", cpath.as_str()),
source: e,
}
})?;
let body = msg.body();
let all: HashMap<String, HashMap<String, Value>> = body.deserialize()?;
if let Some(conn_section) = all.get("connection")
&& let Some(Value::Str(id)) = conn_section.get("id")
&& id == name
{
return Ok(Some(cpath));
}
}
Ok(None)
}
fn should_skip_lookup(name: &str) -> Result<bool> {
if name.trim().is_empty() {
return Ok(true);
}
validate_connection_name(name)?;
Ok(false)
}
pub(crate) async fn has_saved_connection(conn: &Connection, ssid: &str) -> Result<bool> {
get_saved_connection_path(conn, ssid)
.await
.map(|p| p.is_some())
}
pub(crate) async fn delete_connection(conn: &Connection, conn_path: OwnedObjectPath) -> Result<()> {
let cproxy = connection_settings_proxy(conn, conn_path.clone()).await?;
cproxy
.call_method("Delete", &())
.await
.map_err(|e| ConnectionError::DbusOperation {
context: format!("failed to delete connection {}", conn_path.as_str()),
source: e,
})?;
debug!("Deleted connection: {}", conn_path.as_str());
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn saved_connection_lookup_allows_vpn_names_longer_than_ssids() {
let name = "gw-UDP4-1199-namme.lastname-config";
assert!(name.len() > 32);
assert!(!should_skip_lookup(name).unwrap());
}
#[test]
fn saved_connection_lookup_skips_blank_names() {
assert!(should_skip_lookup("").unwrap());
assert!(should_skip_lookup(" ").unwrap());
}
}