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 }
49}
50pub 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}