ic_auth_client/storage/sync_storage/
keyring.rs

1//! OS keyring-backed storage for native environments.
2
3use crate::storage::{DecodeError, StorageError, StoredKey, sync_storage::AuthClientStorage};
4use keyring::Entry;
5
6const KEYRING_STORAGE_PREFIX: &str = "ic-";
7
8/// Implementation of [`AuthClientStorage`].
9#[derive(Debug, Clone)]
10pub struct KeyringStorage {
11    service_name: String,
12}
13
14impl KeyringStorage {
15    /// Creates a new instance of [`KeyringStorage`].
16    pub fn new<T>(service_name: T) -> Self
17    where
18        T: Into<String>,
19    {
20        Self {
21            service_name: service_name.into(),
22        }
23    }
24}
25
26impl AuthClientStorage for KeyringStorage {
27    fn get(&mut self, key: &str) -> Result<Option<StoredKey>, StorageError> {
28        let key = format!("{}{}", KEYRING_STORAGE_PREFIX, key);
29        let entry = Entry::new(&self.service_name, &key)?;
30        match entry.get_secret() {
31            Ok(value) => {
32                if value.len() == 32 {
33                    let bytes: [u8; 32] = value.try_into().map_err(|_| {
34                        StorageError::Decode(DecodeError::Ed25519(
35                            "Invalid slice length".to_string(),
36                        ))
37                    })?;
38                    Ok(Some(StoredKey::Raw(bytes)))
39                } else {
40                    let string = String::from_utf8(value)
41                        .map_err(|e| StorageError::Decode(DecodeError::Ed25519(e.to_string())))?;
42                    Ok(Some(StoredKey::String(string)))
43                }
44            }
45            Err(keyring::Error::NoEntry) => Ok(None),
46            Err(e) => Err(e.into()),
47        }
48    }
49
50    fn set(&mut self, key: &str, value: StoredKey) -> Result<(), StorageError> {
51        let key = format!("{}{}", KEYRING_STORAGE_PREFIX, key);
52        let entry = Entry::new(&self.service_name, &key)?;
53        let bytes: Vec<u8> = match value {
54            StoredKey::String(string) => string.into_bytes(),
55            StoredKey::Raw(value) => value.to_vec(),
56        };
57        entry.set_secret(&bytes)?;
58        Ok(())
59    }
60
61    fn remove(&mut self, key: &str) -> Result<(), StorageError> {
62        let key = format!("{}{}", KEYRING_STORAGE_PREFIX, key);
63        let entry = Entry::new(&self.service_name, &key)?;
64        match entry.delete_credential() {
65            Ok(_) => Ok(()),
66            Err(keyring::Error::NoEntry) => Ok(()),
67            Err(e) => Err(e.into()),
68        }
69    }
70}
71
72impl From<KeyringStorage> for Box<dyn AuthClientStorage> {
73    fn from(storage: KeyringStorage) -> Self {
74        Box::new(storage)
75    }
76}