keyring_core/sample/
credential.rs1use std::any::Any;
2use std::collections::HashMap;
3use std::sync::Arc;
4
5use dashmap::DashMap;
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9use super::store::{CredValue, Store};
10use crate::attributes::parse_attributes;
11use crate::{Credential, Entry, Error, Result, api::CredentialApi};
12
13#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
15pub struct CredId {
16 pub service: String,
17 pub user: String,
18}
19
20#[derive(Clone)]
30pub struct CredKey {
31 pub store: Arc<Store>,
32 pub id: CredId,
33 pub uuid: Option<String>,
34}
35
36impl std::fmt::Debug for CredKey {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 f.debug_struct("CredKey")
39 .field("id", &self.id)
40 .field("uuid", &self.uuid)
41 .finish()
42 }
43}
44
45impl CredKey {
46 pub fn with_unique_pair<T, F>(&self, f: F) -> Result<T>
55 where
56 F: FnOnce(&String, &mut CredValue) -> T,
57 {
58 match self.uuid.as_ref() {
59 Some(key) => match self.store.creds.get(&self.id) {
61 None => Err(Error::NoEntry),
62 Some(pair) => match pair.value().get_mut(key) {
63 None => Err(Error::NoEntry),
64 Some(mut cred) => {
65 let (key, val) = cred.pair_mut();
66 Ok(f(key, val))
67 }
68 },
69 },
70 None => {
72 match self.store.creds.get(&self.id) {
73 None => Err(Error::NoEntry),
75 Some(pair) => {
77 let creds = pair.value();
78 match creds.len() {
79 0 => Err(Error::NoEntry),
81 1 => {
83 let mut first = creds.iter_mut().next().unwrap();
84 let (key, val) = first.pair_mut();
85 Ok(f(key, val))
86 }
87 _ => {
89 let mut entries: Vec<Entry> = vec![];
90 for cred in creds.iter() {
91 let key = CredKey {
92 store: self.store.clone(),
93 id: self.id.clone(),
94 uuid: Some(cred.key().clone()),
95 };
96 entries.push(Entry::new_with_credential(Arc::new(key)));
97 }
98 Err(Error::Ambiguous(entries))
99 }
100 }
101 }
102 }
103 }
104 }
105 }
106
107 pub fn with_unique_cred<T, F>(&self, f: F) -> Result<T>
109 where
110 F: FnOnce(&mut CredValue) -> T,
111 {
112 self.with_unique_pair(|_, cred| f(cred))
113 }
114
115 pub fn get_uuid(&self) -> Result<String> {
117 self.with_unique_pair(|uuid, _| uuid.to_string())
118 }
119
120 pub fn get_comment(&self) -> Result<Option<String>> {
122 self.with_unique_pair(|_, cred| cred.comment.clone())
123 }
124}
125
126impl CredentialApi for CredKey {
127 fn set_secret(&self, secret: &[u8]) -> Result<()> {
129 let result = self.with_unique_cred(|cred| cred.secret = secret.to_vec());
130 match result {
131 Ok(_) => Ok(()),
132 Err(Error::NoEntry) if self.uuid.is_none() => {
134 let value = CredValue::new(secret);
135 let creds = DashMap::new();
136 creds.insert(Uuid::new_v4().to_string(), value);
137 self.store.creds.insert(self.id.clone(), creds);
138 Ok(())
139 }
140 Err(e) => Err(e),
142 }
143 }
144
145 fn get_secret(&self) -> Result<Vec<u8>> {
147 self.with_unique_cred(|cred| cred.secret.clone())
148 }
149
150 fn get_attributes(&self) -> Result<HashMap<String, String>> {
155 self.with_unique_pair(|uuid, cred| get_attrs(uuid, cred))
156 }
157
158 fn update_attributes(&self, attrs: &HashMap<&str, &str>) -> Result<()> {
162 parse_attributes(&["comment"], Some(attrs))?;
163 self.with_unique_cred(|cred| update_attrs(cred, attrs))
164 }
165
166 fn delete_credential(&self) -> Result<()> {
168 let result = self.with_unique_cred(|_| ());
169 match result {
170 Ok(_) => {
172 match self.uuid.as_ref() {
173 Some(uuid) => {
175 self.store.creds.get(&self.id).unwrap().value().remove(uuid);
176 Ok(())
177 }
178 None => {
180 self.store.creds.remove(&self.id);
181 Ok(())
182 }
183 }
184 }
185 Err(e) => Err(e),
187 }
188 }
189
190 fn get_credential(&self) -> Result<Option<Arc<Credential>>> {
195 let result = self.get_uuid();
196 match result {
197 Ok(uuid) => Ok(Some(Arc::new(CredKey {
198 store: self.store.clone(),
199 id: self.id.clone(),
200 uuid: Some(uuid),
201 }))),
202 Err(e) => Err(e),
203 }
204 }
205
206 fn get_specifiers(&self) -> Option<(String, String)> {
208 Some((self.id.service.clone(), self.id.user.clone()))
209 }
210
211 fn as_any(&self) -> &dyn Any {
213 self
214 }
215
216 fn debug_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218 std::fmt::Debug::fmt(self, f)
219 }
220}
221
222pub fn get_attrs(uuid: &str, cred: &CredValue) -> HashMap<String, String> {
226 let mut attrs = HashMap::new();
227 attrs.insert("uuid".to_string(), uuid.to_string());
228 if cred.creation_date.is_some() {
229 attrs.insert(
230 "creation-date".to_string(),
231 cred.creation_date.as_ref().unwrap().to_string(),
232 );
233 }
234 if cred.comment.is_some() {
235 attrs.insert(
236 "comment".to_string(),
237 cred.comment.as_ref().unwrap().to_string(),
238 );
239 };
240 attrs
241}
242
243pub fn update_attrs(cred: &mut CredValue, attrs: &HashMap<&str, &str>) {
247 if let Some(comment) = attrs.get("comment") {
248 cred.comment = Some(comment.to_string());
249 }
250}