windows_native_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, Error, Result};
8
9use crate::cred::Cred;
10
11#[derive(Debug, Clone)]
13pub struct Store {
14 pub id: String,
15 pub delimiters: [String; 3],
16 pub service_no_divider: bool,
17}
18
19impl Store {
20 pub fn new() -> Result<Arc<Self>> {
25 Ok(Self::new_internal(
26 ["".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("")
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 = match config.get("service_no_divider").map(|s| s.as_str()) {
59 None => false,
60 Some("true") => true,
61 Some("false") => false,
62 Some(_) => {
63 return Err(Error::Invalid(
64 "service_no_divider".to_string(),
65 "must be true or false".to_string(),
66 ));
67 }
68 };
69 Ok(Self::new_internal(
70 [prefix, divider, suffix],
71 service_no_divider,
72 ))
73 }
74
75 fn new_internal(delimiters: [String; 3], service_no_divider: bool) -> Arc<Self> {
76 let now = SystemTime::now();
77 let elapsed = if now.lt(&UNIX_EPOCH) {
78 UNIX_EPOCH.duration_since(now).unwrap()
79 } else {
80 now.duration_since(UNIX_EPOCH).unwrap()
81 };
82 Arc::new(Store {
83 id: format!(
84 "Crate version {}, Instantiated at {}",
85 env!("CARGO_PKG_VERSION"),
86 elapsed.as_secs_f64()
87 ),
88 delimiters,
89 service_no_divider,
90 })
91 }
92}
93
94impl CredentialStoreApi for Store {
95 fn vendor(&self) -> String {
97 "Windows Credential Manager, https://crates.io/crates/windows-native-keyring-store"
98 .to_string()
99 }
100
101 fn id(&self) -> String {
103 self.id.clone()
104 }
105
106 fn build(
111 &self,
112 service: &str,
113 user: &str,
114 modifiers: Option<&HashMap<&str, &str>>,
115 ) -> Result<Entry> {
116 let mods = parse_attributes(&["target"], modifiers)?;
117 let target = mods.get("target").map(|s| s.as_str());
118 let cred = Cred::build_from_specifiers(
119 target,
120 &self.delimiters,
121 self.service_no_divider,
122 service,
123 user,
124 )?;
125 Ok(Entry::new_with_credential(Arc::new(cred)))
126 }
127
128 fn as_any(&self) -> &dyn std::any::Any {
130 self
131 }
132
133 fn persistence(&self) -> CredentialPersistence {
137 CredentialPersistence::UntilDelete
138 }
139
140 fn debug_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 std::fmt::Debug::fmt(self, f)
143 }
144}