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