linux_keyutils_keyring_store/
store.rs

1use 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/// The builder for keyutils credentials
13#[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    /// Create the default store: prefix `keyring:`, divider '@', no suffix.
22    ///
23    /// This is the configuration that matches the legacy keyring for this store.
24    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    /// Create a custom-configured store.
32    ///
33    /// The delimiter config options are `prefix`, `divider`, and `suffix`. They
34    /// default to `keyring:`, `@`, and the empty string, respectively.
35    ///
36    /// If you want to be sure that key descriptions cannot be ambiguous, specify
37    /// the config option `service_no_divider` to `true`.
38    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    /// See the keyring-core API docs.
90    fn vendor(&self) -> String {
91        "Linux keyutils, https://crates.io/crates/linux-keyutils-keyring-store".to_string()
92    }
93
94    /// See the keyring-core API docs.
95    fn id(&self) -> String {
96        self.id.clone()
97    }
98
99    /// See the keyring-core API docs.
100    ///
101    /// Building a credential does not create a key in the store.
102    /// It's setting a password that does that.
103    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    /// See the keyring-core API docs.
122    fn as_any(&self) -> &dyn std::any::Any {
123        self
124    }
125
126    /// See the keyring-core API docs.
127    ///
128    /// Since this keystore keeps credentials in kernel memory, they vanish on reboot
129    fn persistence(&self) -> CredentialPersistence {
130        CredentialPersistence::UntilReboot
131    }
132
133    /// See the keychain-core API docs.
134    fn debug_fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
135        std::fmt::Debug::fmt(self, f)
136    }
137}