use crate::cfg::PasswordManager;
use zbus::Connection;
pub struct KWalletClient {
connection: Connection,
handle: i32,
destination: Option<&'static str>,
path: &'static str,
iface: Option<&'static str>,
app_name: &'static str,
folder: &'static str,
}
pub fn open() -> zbus::Result<KWalletClient> {
let destination = Some("org.kde.kwalletd5");
let path = "/modules/kwalletd5";
let iface = Some("org.kde.KWallet");
let app_name = "de.lu-fennell.icinga-client";
let folder = app_name;
let c = Connection::new_session()?;
let handle: i32 = c
.call_method(
destination,
path,
iface,
"open",
&("kdewallet", 0i64, app_name),
)?
.body()?;
Ok(KWalletClient {
connection: c,
handle,
destination,
path,
iface,
app_name,
folder,
})
}
impl KWalletClient {
fn close(&self) -> zbus::Result<()> {
self.connection.call_method(
self.destination,
self.path,
self.iface,
"close",
&(self.handle, false, self.app_name),
)?;
Ok(())
}
pub fn create_folder(&self) -> zbus::Result<()> {
self.connection.call_method(
self.destination,
self.path,
self.iface,
"createFolder",
&(self.handle, self.folder, self.app_name),
)?;
Ok(())
}
pub fn write_password(&self, key: &str, password: &str) -> zbus::Result<()> {
self.connection.call_method(
self.destination,
self.path,
self.iface,
"writePassword",
&(self.handle, self.folder, key, password, self.app_name),
)?;
Ok(())
}
pub fn read_password(&self, key: &str) -> zbus::Result<String> {
let password = self
.connection
.call_method(
self.destination,
self.path,
self.iface,
"readPassword",
&(self.handle, self.folder, key, self.app_name),
)?
.body()?;
Ok(password)
}
pub fn remove_entry(&self, key: &str) -> zbus::Result<()> {
self.connection.call_method(
self.destination,
self.path,
self.iface,
"removeEntry",
&(self.handle, self.folder, key, self.app_name),
)?;
Ok(())
}
pub fn has_entry(&self, key: &str) -> zbus::Result<bool> {
let result: bool = self
.connection
.call_method(
self.destination,
self.path,
self.iface,
"hasEntry",
&(self.handle, self.folder, key, self.app_name),
)?
.body()?;
Ok(result)
}
}
impl Drop for KWalletClient {
fn drop(&mut self) {
if let Err(e) = self.close() {
eprintln!("Failed to close kwallet: {}", e);
}
}
}
impl PasswordManager for KWalletClient {
fn load_password(
&self,
host: &str,
user: &str,
) -> Result<Option<String>, Box<dyn std::error::Error>> {
let key = key(host, user);
let has_entry = self.has_entry(&key)?;
if has_entry {
let password = self.read_password(&key)?;
Ok(Some(password))
} else {
Ok(None)
}
}
fn name(&self) -> String {
"kwallet".to_string()
}
fn store_password(
&self,
host: &str,
user: &str,
password: &str,
) -> Result<(), Box<dyn std::error::Error>> {
Ok(self.write_password(&key(host, user), password)?)
}
}
fn key(host: &str, user: &str) -> String {
format!("{}@{}", user, host)
}