From de29404d12a60a1021481bf22e9a27797fc170b9 Mon Sep 17 00:00:00 2001 From: Dhanuka Warusadura Date: Sun, 3 Nov 2024 23:23:50 +0530 Subject: [PATCH] server: Add GetSecret, GetSecrets and SetSecret implementation Signed-off-by: Dhanuka Warusadura --- server/src/collection.rs | 12 ++++++ server/src/item.rs | 79 ++++++++++++++++++++++++++++++++--- server/src/service.rs | 33 +++++++++++++-- server/src/service_manager.rs | 4 ++ server/src/session.rs | 8 +++- 5 files changed, 125 insertions(+), 11 deletions(-) diff --git a/server/src/collection.rs b/server/src/collection.rs index 8fec5f72..d3f40265 100644 --- a/server/src/collection.rs +++ b/server/src/collection.rs @@ -193,6 +193,18 @@ impl Collection { items } + pub async fn item_from_path(&self, path: &OwnedObjectPath) -> Option { + let items = self.items.lock().await; + + for item in items.iter() { + if item.path() == path { + return Some(item.clone()); + } + } + + None + } + pub async fn dispatch_items(&self) -> Result<(), Error> { let keyring_items = self.keyring.items().await; let mut items = self.items.lock().await; diff --git a/server/src/item.rs b/server/src/item.rs index 38b832cf..163e559f 100644 --- a/server/src/item.rs +++ b/server/src/item.rs @@ -20,7 +20,7 @@ pub struct Item { locked: Arc, inner: Arc>, // Other attributes - _manager: Arc>, + manager: Arc>, path: OwnedObjectPath, } @@ -32,12 +32,79 @@ impl Item { } #[zbus(out_args("secret"))] - pub async fn get_secret(&self, _session: ObjectPath<'_>) -> Result { - todo!() + pub async fn get_secret( + &self, + session: OwnedObjectPath, + ) -> Result<(SecretInner,), ServiceError> { + let manager = self.manager.lock().await; + + let Some(session) = manager.session(&session) else { + tracing::error!("The session `{}` does not exist.", session); + return Err(ServiceError::NoSession(format!( + "The session `{}` does not exist.", + session + ))); + }; + + if self.is_locked().await { + tracing::error!("Cannot get secret of a locked object `{}`", self.path); + return Err(ServiceError::IsLocked(format!( + "Cannot get secret of a locked object `{}`.", + self.path + ))); + } + + let inner = self.inner.lock().await; + let secret = inner.secret(); + + tracing::debug!("Secret retrieved from the item: {}.", self.path); + + match session.aes_key() { + Some(key) => { + let iv = oo7::crypto::generate_iv(); + let encrypted = oo7::crypto::encrypt(secret, &key, &iv); + + Ok((SecretInner( + session.path().clone(), + iv, + encrypted, + "text/plain".to_owned(), + ),)) + } + None => Ok((SecretInner( + session.path().clone(), + Vec::new(), + secret.to_vec(), + "text/plain".to_owned(), + ),)), + } } - pub async fn set_secret(&self, _secret: SecretInner) -> Result<(), ServiceError> { - todo!() + pub async fn set_secret(&self, secret: SecretInner) -> Result<(), ServiceError> { + let SecretInner(session, iv, secret, _content_type) = secret; + let manager = self.manager.lock().await; + + let Some(session) = manager.session(&session) else { + tracing::error!("The session `{}` does not exist.", session); + return Err(ServiceError::NoSession(format!( + "The session `{}` does not exist.", + session + ))); + }; + + let mut inner = self.inner.lock().await; + + match session.aes_key() { + Some(key) => { + let decrypted = oo7::crypto::decrypt(secret, &key, &iv); + inner.set_secret(decrypted); + } + None => { + inner.set_secret(secret); + } + } + + Ok(()) } #[zbus(property, name = "Locked")] @@ -94,7 +161,7 @@ impl Item { locked: Arc::new(AtomicBool::new(locked)), inner: Arc::new(Mutex::new(item)), path: OwnedObjectPath::try_from(format!("{}/{}", collection_path, item_index)).unwrap(), - _manager: manager, + manager, } } diff --git a/server/src/service.rs b/server/src/service.rs index 31d246cd..e3c73a30 100644 --- a/server/src/service.rs +++ b/server/src/service.rs @@ -131,10 +131,37 @@ impl Service { #[zbus(out_args("secrets"))] pub async fn get_secrets( &self, - _items: Vec, - _session: ObjectPath<'_>, + items: Vec, + session: OwnedObjectPath, ) -> Result, ServiceError> { - todo!() + let mut secrets = HashMap::new(); + let collections = self.collections.lock().await; + + 'outer: for collection in collections.iter() { + for item in &items { + if let Some(item) = collection.item_from_path(item).await { + match item.get_secret(session.clone()).await { + Ok((secret,)) => { + secrets.insert(item.path().clone(), secret); + // To avoid iterating through all the remaining collections, if the + // items secrets are already retrieved. + if secrets.len() == items.len() { + break 'outer; + } + } + // Avoid erroring out if an item is locked. + Err(ServiceError::IsLocked(_)) => { + continue; + } + Err(err) => { + return Err(err); + } + }; + } + } + } + + Ok(secrets) } #[zbus(out_args("collection"))] diff --git a/server/src/service_manager.rs b/server/src/service_manager.rs index 5435d8f0..4483442e 100644 --- a/server/src/service_manager.rs +++ b/server/src/service_manager.rs @@ -29,6 +29,10 @@ impl ServiceManager { self.sessions.len() } + pub fn session(&self, path: &OwnedObjectPath) -> Option> { + self.sessions.get(path).map(Arc::clone) + } + pub fn insert_session(&mut self, path: OwnedObjectPath, session: Arc) { self.sessions.insert(path, session); } diff --git a/server/src/session.rs b/server/src/session.rs index a3537198..d2aa42fa 100644 --- a/server/src/session.rs +++ b/server/src/session.rs @@ -10,7 +10,7 @@ use crate::service_manager::ServiceManager; #[derive(Debug, Clone)] pub struct Session { - _aes_key: Option>, + aes_key: Option>, manager: Arc>, path: OwnedObjectPath, } @@ -34,7 +34,7 @@ impl Session { Self { path: OwnedObjectPath::try_from(format!("/org/freedesktop/secrets/session/s{index}")) .unwrap(), - _aes_key: aes_key, + aes_key, manager, } } @@ -42,4 +42,8 @@ impl Session { pub fn path(&self) -> &OwnedObjectPath { &self.path } + + pub fn aes_key(&self) -> Option> { + self.aes_key.as_ref().map(Arc::clone) + } }