linux_keyutils_keyring_store/
store.rs1use std::collections::HashMap;
2use std::sync::Arc;
3use std::time::{SystemTime, UNIX_EPOCH};
4
5use keyring_core::api::{CredentialPersistence, CredentialStoreApi};
6use keyring_core::attributes::parse_attributes;
7use keyring_core::{Entry, Result};
8
9use super::Cred;
10
11#[derive(Clone)]
13pub struct Store {
14 pub id: String,
15 pub delimiters: [String; 3],
16 pub service_no_divider: bool,
17}
18
19impl std::fmt::Debug for Store {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 f.debug_struct("Store")
22 .field("vendor", &self.vendor())
23 .field("id", &self.id())
24 .field("delimiters", &self.delimiters)
25 .field("service_no_divider", &self.service_no_divider)
26 .finish()
27 }
28}
29
30impl Store {
31 pub fn new() -> Result<Arc<Self>> {
35 Ok(Self::new_internal(
36 ["keyring:".to_string(), "@".to_string(), "".to_string()],
37 false,
38 ))
39 }
40
41 pub fn new_with_configuration(config: &HashMap<&str, &str>) -> Result<Arc<Self>> {
49 let config = parse_attributes(
50 &["prefix", "divider", "suffix", "*service_no_divider"],
51 Some(config),
52 )?;
53 let prefix = config
54 .get("prefix")
55 .map(|s| s.as_str())
56 .unwrap_or("keyring:")
57 .to_string();
58 let divider = config
59 .get("divider")
60 .map(|s| s.as_str())
61 .unwrap_or("@")
62 .to_string();
63 let suffix = config
64 .get("suffix")
65 .map(|s| s.as_str())
66 .unwrap_or("")
67 .to_string();
68 let service_no_divider = config
69 .get("service_no_divider")
70 .map(|s| s.as_str())
71 .unwrap_or("false")
72 .eq("true");
73 Ok(Self::new_internal(
74 [prefix, divider, suffix],
75 service_no_divider,
76 ))
77 }
78
79 fn new_internal(delimiters: [String; 3], service_no_divider: bool) -> Arc<Self> {
80 let now = SystemTime::now();
81 let elapsed = if now.lt(&UNIX_EPOCH) {
82 UNIX_EPOCH.duration_since(now).unwrap()
83 } else {
84 now.duration_since(UNIX_EPOCH).unwrap()
85 };
86 Arc::new(Store {
87 id: format!(
88 "Crate version {}, Instantiated at {}",
89 env!("CARGO_PKG_VERSION"),
90 elapsed.as_secs_f64()
91 ),
92 delimiters,
93 service_no_divider,
94 })
95 }
96}
97
98impl CredentialStoreApi for Store {
99 fn vendor(&self) -> String {
101 "Linux keyutils, https://crates.io/crates/linux-keyutils-keyring-store".to_string()
102 }
103
104 fn id(&self) -> String {
106 self.id.clone()
107 }
108
109 fn build(
114 &self,
115 service: &str,
116 user: &str,
117 modifiers: Option<&HashMap<&str, &str>>,
118 ) -> Result<Entry> {
119 let mods = parse_attributes(&["description"], modifiers)?;
120 let description = mods.get("description").map(|s| s.as_str());
121 let cred = Cred::build_from_specifiers(
122 description,
123 &self.delimiters,
124 self.service_no_divider,
125 service,
126 user,
127 )?;
128 Ok(Entry::new_with_credential(Arc::new(cred)))
129 }
130
131 fn as_any(&self) -> &dyn std::any::Any {
133 self
134 }
135
136 fn persistence(&self) -> CredentialPersistence {
140 CredentialPersistence::UntilReboot
141 }
142
143 fn debug_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 std::fmt::Debug::fmt(self, f)
146 }
147}