1#![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
17use 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 pub fn list_keys(&self, _service: &str) -> Result<Vec<String>> {
49 Err(KeyringError::NoBackendFound)
50 }
51 }
52 }
53}
54pub trait Keyring {
62 fn set_value(&mut self, value: &str) -> Result<()>;
64 fn get_value(&self) -> Result<String>;
66 fn delete_value(&mut self) -> Result<()>;
68}
69
70enum KeyringManagerKind {
71 #[allow(dead_code)]
72 Secure(PlatformKeyringManager),
73 Insecure(InsecureKeyringManager),
74}
75
76pub struct KeyringManager {
77 kind: KeyringManagerKind,
78}
79
80impl KeyringManager {
81 cfg_if! {
82 if #[cfg(all(target_os = "macos", feature = "macos-specify-keychain"))] {
83 pub fn new_secure_with_path(application: &str, path: &Path) -> Result<Self> {
85 Ok(KeyringManager {
86 kind: KeyringManagerKind::Secure(PlatformKeyringManager::with_path(application, path)?),
87 })
88 }
89 }
90 }
91 cfg_if! {
92 if #[cfg(target_os = "android")] {
93 pub fn new_secure(application: &str, context: AndroidKeyringContext) -> Result<Self> {
95 Ok(KeyringManager {
96 kind: KeyringManagerKind::Secure(PlatformKeyringManager::new(application, context)?),
97 })
98 }
99 } else if #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos", target_os = "ios"))] {
100 pub fn new_secure(application: &str) -> Result<Self> {
102 Ok(KeyringManager {
103 kind: KeyringManagerKind::Secure(PlatformKeyringManager::new(application)?),
104 })
105 }
106 } else {
107 pub fn new_secure(_application: &str) -> Result<Self> {
109 Err(KeyringError::NoBackendFound)
110 }
111 }
112 }
113
114 pub fn new_insecure(application: &str, insecure_keyring_file: &Path) -> Result<Self> {
116 Ok(KeyringManager {
117 kind: KeyringManagerKind::Insecure(InsecureKeyringManager::new(
118 application,
119 insecure_keyring_file,
120 )?),
121 })
122 }
123
124 pub fn with_keyring<F, T>(&self, service: &str, key: &str, f: F) -> Result<T>
126 where
127 F: FnOnce(&mut dyn Keyring) -> Result<T>,
128 {
129 match &self.kind {
130 KeyringManagerKind::Secure(pkm) => pkm.with_keyring(service, key, f),
131 KeyringManagerKind::Insecure(ikm) => ikm.with_keyring(service, key, f),
132 }
133 }
134
135 pub fn list_keys(&self, service: &str) -> Result<Vec<String>> {
141 match &self.kind {
142 KeyringManagerKind::Secure(pkm) => pkm.list_keys(service),
143 KeyringManagerKind::Insecure(ikm) => ikm.list_keys(service),
144 }
145 }
146}
147
148pub(crate) fn map_to_generic<E: std::fmt::Display>(e: E) -> KeyringError {
149 KeyringError::Generic(format!("{}", e))
150}
151
152pub(crate) fn map_log_err<T: std::error::Error>(e: T) -> T {
153 error!("{}", e);
154 e
155}
156
157cfg_if! {
158 if #[cfg(test)] {
159 mod tests;
160 } else if #[cfg(feature="keyring_manager_android_tests")] {
161 pub mod tests;
162 } else if #[cfg(feature="keyring_manager_ios_tests")] {
163 pub mod tests;
164 }
165}