Skip to content

Commit ed96e28

Browse files
committed
server: Add GetSecret, GetSecrets and SetSecret implementation
This change adds Secret Service method GetSecrets and Secret Item methods GetSecret and SetSecret. Signed-off-by: Dhanuka Warusadura <dhanuka@gnome.org>
1 parent f097dc5 commit ed96e28

File tree

5 files changed

+130
-11
lines changed

5 files changed

+130
-11
lines changed

server/src/collection.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,18 @@ impl Collection {
193193
items
194194
}
195195

196+
pub async fn item_from_path(&self, path: &OwnedObjectPath) -> Option<item::Item> {
197+
let items = self.items.lock().await;
198+
199+
for item in items.iter() {
200+
if item.path() == path {
201+
return Some(item.clone());
202+
}
203+
}
204+
205+
None
206+
}
207+
196208
pub async fn dispatch_items(&self) -> Result<(), Error> {
197209
let keyring_items = self.keyring.items().await;
198210
let mut items = self.items.lock().await;

server/src/item.rs

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub struct Item {
2020
locked: Arc<AtomicBool>,
2121
inner: Arc<Mutex<oo7::portal::Item>>,
2222
// Other attributes
23-
_manager: Arc<Mutex<ServiceManager>>,
23+
manager: Arc<Mutex<ServiceManager>>,
2424
path: OwnedObjectPath,
2525
}
2626

@@ -32,12 +32,83 @@ impl Item {
3232
}
3333

3434
#[zbus(out_args("secret"))]
35-
pub async fn get_secret(&self, _session: ObjectPath<'_>) -> Result<SecretInner, ServiceError> {
36-
todo!()
35+
pub async fn get_secret(
36+
&self,
37+
session: OwnedObjectPath,
38+
) -> Result<(SecretInner,), ServiceError> {
39+
let manager = self.manager.lock().await;
40+
41+
let Some(session) = manager.session(&session) else {
42+
tracing::error!("The session `{}` does not exist.", session);
43+
return Err(ServiceError::NoSession(format!(
44+
"The session `{}` does not exist.",
45+
session
46+
)));
47+
};
48+
49+
if self.is_locked().await {
50+
tracing::error!("Cannot get secret of a locked object `{}`", self.path);
51+
return Err(ServiceError::IsLocked(format!(
52+
"Cannot get secret of a locked object `{}`.",
53+
self.path
54+
)));
55+
}
56+
57+
let inner = self.inner.lock().await;
58+
let secret = inner.secret();
59+
60+
tracing::debug!("Secret retrieved from the item: {}.", self.path);
61+
62+
match session.aes_key() {
63+
Some(key) => {
64+
let iv = oo7::crypto::generate_iv();
65+
let encrypted = oo7::crypto::encrypt(secret, &key, &iv);
66+
67+
Ok((SecretInner(
68+
session.path().clone(),
69+
iv,
70+
encrypted,
71+
"text/plain".to_owned(),
72+
),))
73+
}
74+
None => Ok((SecretInner(
75+
session.path().clone(),
76+
Vec::new(),
77+
secret.to_vec(),
78+
"text/plain".to_owned(),
79+
),)),
80+
}
3781
}
3882

39-
pub async fn set_secret(&self, _secret: SecretInner) -> Result<(), ServiceError> {
40-
todo!()
83+
pub async fn set_secret(&self, secret: SecretInner) -> Result<(), ServiceError> {
84+
let session = secret.0;
85+
let manager = self.manager.lock().await;
86+
87+
let Some(session) = manager.session(&session) else {
88+
tracing::error!("The session `{}` does not exist.", session);
89+
return Err(ServiceError::NoSession(format!(
90+
"The session `{}` does not exist.",
91+
session
92+
)));
93+
};
94+
95+
let mut inner = self.inner.lock().await;
96+
97+
match session.aes_key() {
98+
Some(key) => {
99+
let iv = secret.1;
100+
let secret_encrypted = secret.2;
101+
102+
let decrypted = oo7::crypto::decrypt(secret_encrypted, &key, &iv);
103+
inner.set_secret(decrypted);
104+
}
105+
None => {
106+
let secret_plain = secret.2;
107+
inner.set_secret(secret_plain);
108+
}
109+
}
110+
111+
Ok(())
41112
}
42113

43114
#[zbus(property, name = "Locked")]
@@ -94,7 +165,7 @@ impl Item {
94165
locked: Arc::new(AtomicBool::new(locked)),
95166
inner: Arc::new(Mutex::new(item)),
96167
path: OwnedObjectPath::try_from(format!("{}/{}", collection_path, item_index)).unwrap(),
97-
_manager: manager,
168+
manager,
98169
}
99170
}
100171

server/src/service.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,38 @@ impl Service {
131131
#[zbus(out_args("secrets"))]
132132
pub async fn get_secrets(
133133
&self,
134-
_items: Vec<OwnedObjectPath>,
135-
_session: ObjectPath<'_>,
134+
items: Vec<OwnedObjectPath>,
135+
session: OwnedObjectPath,
136136
) -> Result<HashMap<OwnedObjectPath, SecretInner>, ServiceError> {
137-
todo!()
137+
let mut secrets = HashMap::new();
138+
let collections = self.collections.lock().await;
139+
140+
'outer: for collection in collections.iter() {
141+
for item in &items {
142+
if let Some(item) = collection.item_from_path(item).await {
143+
match item.get_secret(session.clone()).await {
144+
Ok(secret) => {
145+
secrets.insert(item.path().clone(), secret.0);
146+
// To avoid iterating through all the remaining collection, if the items
147+
// secrets are already retrieved.
148+
if secrets.len() == items.len() {
149+
break 'outer;
150+
}
151+
}
152+
// Based on gnome-keyring-daemon behavior, to avoid error out when the item
153+
// is Locked.
154+
Err(ServiceError::IsLocked(_)) => {
155+
continue;
156+
}
157+
Err(err) => {
158+
return Err(err);
159+
}
160+
};
161+
}
162+
}
163+
}
164+
165+
Ok(secrets)
138166
}
139167

140168
#[zbus(out_args("collection"))]

server/src/service_manager.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ impl ServiceManager {
2929
self.sessions.len()
3030
}
3131

32+
pub fn session(&self, path: &OwnedObjectPath) -> Option<Arc<Session>> {
33+
self.sessions.get(path).map(Arc::clone)
34+
}
35+
3236
pub fn insert_session(&mut self, path: OwnedObjectPath, session: Arc<Session>) {
3337
self.sessions.insert(path, session);
3438
}

server/src/session.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::service_manager::ServiceManager;
1010

1111
#[derive(Debug, Clone)]
1212
pub struct Session {
13-
_aes_key: Option<Arc<Key>>,
13+
aes_key: Option<Arc<Key>>,
1414
manager: Arc<Mutex<ServiceManager>>,
1515
path: OwnedObjectPath,
1616
}
@@ -34,12 +34,16 @@ impl Session {
3434
Self {
3535
path: OwnedObjectPath::try_from(format!("/org/freedesktop/secrets/session/s{index}"))
3636
.unwrap(),
37-
_aes_key: aes_key,
37+
aes_key,
3838
manager,
3939
}
4040
}
4141

4242
pub fn path(&self) -> &OwnedObjectPath {
4343
&self.path
4444
}
45+
46+
pub fn aes_key(&self) -> Option<Arc<Key>> {
47+
self.aes_key.as_ref().map(Arc::clone)
48+
}
4549
}

0 commit comments

Comments
 (0)