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