keyring_manager/
lib.rs

1//! # Keyring library
2//!
3//! Allows for setting and getting passwords on Linux, OSX, Windows, and Android
4#![deny(clippy::all)]
5
6use log::*;
7use std::path::Path;
8
9mod error;
10mod escape;
11mod insecure;
12
13pub use error::{KeyringError, Result};
14use escape::*;
15use insecure::InsecureKeyringManager;
16
17/////////////////////////////////////////////////////////////////////////
18
19use cfg_if::*;
20cfg_if! {
21    if #[cfg(target_os = "linux")] {
22        mod linux;
23        use linux::LinuxKeyringManager as PlatformKeyringManager;
24    } else if #[cfg(target_os = "windows")] {
25        mod windows;
26        use windows::WindowsKeyringManager as PlatformKeyringManager;
27    } else if #[cfg(target_os = "macos")] {
28        mod macos;
29        use macos::MacosKeyringManager as PlatformKeyringManager;
30    } else if #[cfg(target_os = "ios")] {
31        mod ios;
32        use ios::IosKeyringManager as PlatformKeyringManager;
33    } else if #[cfg(target_os = "android")] {
34        pub(crate) mod android;
35        use android::AndroidKeyringManager as PlatformKeyringManager;
36        pub use android::AndroidKeyringContext;
37    } else {
38        struct PlatformKeyringManager {}
39
40        impl PlatformKeyringManager {
41            pub fn with_keyring<F, T>(&self, _service: &str, _key: &str, _func: F) -> Result<T>
42            where
43                F: FnOnce(&mut dyn Keyring) -> Result<T>,
44            {
45                Err(KeyringError::NoBackendFound)
46            }
47        }
48    }
49}
50/////////////////////////////////////////////////////////////////////////
51
52pub trait Keyring {
53    fn set_value(&mut self, value: &str) -> Result<()>;
54    fn get_value(&self) -> Result<String>;
55    fn delete_value(&mut self) -> Result<()>;
56}
57
58enum KeyringManagerKind {
59    #[allow(dead_code)]
60    Secure(PlatformKeyringManager),
61    Insecure(InsecureKeyringManager),
62}
63
64pub struct KeyringManager {
65    kind: KeyringManagerKind,
66}
67
68impl KeyringManager {
69    cfg_if! {
70        if #[cfg(all(target_os = "macos", feature = "macos-specify-keychain"))] {
71            pub fn new_secure_with_path(application: &str, path: &Path) -> Result<Self> {
72                Ok(KeyringManager {
73                    kind: KeyringManagerKind::Secure(PlatformKeyringManager::with_path(application, path)?),
74                })
75            }
76        }
77    }
78    cfg_if! {
79        if #[cfg(target_os = "android")] {
80            pub fn new_secure(application: &str, context: AndroidKeyringContext) -> Result<Self> {
81                Ok(KeyringManager {
82                    kind: KeyringManagerKind::Secure(PlatformKeyringManager::new(application, context)?),
83                })
84            }
85        } else if #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos", target_os = "ios"))] {
86            pub fn new_secure(application: &str) -> Result<Self> {
87                Ok(KeyringManager {
88                    kind: KeyringManagerKind::Secure(PlatformKeyringManager::new(application)?),
89                })
90            }
91        } else {
92            pub fn new_secure(_application: &str) -> Result<Self> {
93                Err(KeyringError::NoBackendFound)
94            }
95        }
96    }
97
98    pub fn new_insecure(application: &str, insecure_keyring_file: &Path) -> Result<Self> {
99        Ok(KeyringManager {
100            kind: KeyringManagerKind::Insecure(InsecureKeyringManager::new(
101                application,
102                insecure_keyring_file,
103            )?),
104        })
105    }
106
107    pub fn with_keyring<F, T>(&self, service: &str, key: &str, f: F) -> Result<T>
108    where
109        F: FnOnce(&mut dyn Keyring) -> Result<T>,
110    {
111        match &self.kind {
112            KeyringManagerKind::Secure(pkm) => pkm.with_keyring(service, key, f),
113            KeyringManagerKind::Insecure(ikm) => ikm.with_keyring(service, key, f),
114        }
115    }
116}
117
118pub(crate) fn map_to_generic<E: std::fmt::Display>(e: E) -> KeyringError {
119    KeyringError::Generic(format!("{}", e))
120}
121
122pub(crate) fn map_log_err<T: std::error::Error>(e: T) -> T {
123    error!("{}", e);
124    e
125}
126
127cfg_if! {
128    if #[cfg(test)] {
129        mod tests;
130    } else if #[cfg(feature="keyring_manager_android_tests")] {
131        pub mod tests;
132    } else if #[cfg(feature="keyring_manager_ios_tests")] {
133        pub mod tests;
134    }
135}