1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! # Keyring library
//!
//! Allows for setting and getting passwords on Linux, OSX, Windows, and Android
#![deny(clippy::all)]

use log::*;
use std::path::Path;

/////////////////////////////////////////////////////////////////////////

use cfg_if::*;
cfg_if! {
    if #[cfg(target_os = "linux")] {
        mod linux;
        use linux::LinuxKeyringManager as PlatformKeyringManager;
    } else if #[cfg(target_os = "windows")] {
        mod windows;
        use windows::WindowsKeyringManager as PlatformKeyringManager;
    } else if #[cfg(target_os = "macos")] {
        mod macos;
        use macos::MacosKeyringManager as PlatformKeyringManager;
    } else if #[cfg(target_os = "ios")] {
        mod ios;
        use ios::IosKeyringManager as PlatformKeyringManager;
    } else if #[cfg(target_os = "android")] {
        pub(crate) mod android;
        use android::AndroidKeyringManager as PlatformKeyringManager;
        pub use android::AndroidKeyringContext;
    }
}

mod insecure;
use insecure::InsecureKeyringManager;

/////////////////////////////////////////////////////////////////////////

pub trait Keyring {
    fn set_value(&mut self, value: &str) -> Result<()>;
    fn get_value(&self) -> Result<String>;
    fn delete_value(&mut self) -> Result<()>;
}

pub enum KeyringManagerKind {
    Secure(PlatformKeyringManager),
    Insecure(InsecureKeyringManager),
}

pub struct KeyringManager {
    kind: KeyringManagerKind,
}

impl KeyringManager {
    cfg_if! {
        if #[cfg(all(target_os = "macos", feature = "macos-specify-keychain"))] {
            pub fn new_secure_with_path(application: &str, path: &Path) -> Result<Self> {
                Ok(KeyringManager {
                    kind: KeyringManagerKind::Secure(PlatformKeyringManager::with_path(application, path)?),
                })
            }
        }
    }
    cfg_if! {
        if #[cfg(target_os = "android")] {
            pub fn new_secure(application: &str, context: AndroidKeyringContext) -> Result<Self> {
                Ok(KeyringManager {
                    kind: KeyringManagerKind::Secure(PlatformKeyringManager::new(application, context)?),
                })
            }
        } else {
            pub fn new_secure(application: &str) -> Result<Self> {
                Ok(KeyringManager {
                    kind: KeyringManagerKind::Secure(PlatformKeyringManager::new(application)?),
                })
            }
        }
    }

    pub fn new_insecure(application: &str, insecure_keyring_file: &Path) -> Result<Self> {
        Ok(KeyringManager {
            kind: KeyringManagerKind::Insecure(InsecureKeyringManager::new(
                application,
                insecure_keyring_file,
            )?),
        })
    }

    pub fn with_keyring<F, T>(&self, service: &str, key: &str, f: F) -> Result<T>
    where
        F: FnOnce(&mut dyn Keyring) -> Result<T>,
    {
        match &self.kind {
            KeyringManagerKind::Secure(pkm) => pkm.with_keyring(service, key, f),
            KeyringManagerKind::Insecure(ikm) => ikm.with_keyring(service, key, f),
        }
    }
}

pub(crate) fn map_to_generic<E: std::fmt::Display>(e: E) -> KeyringError {
    KeyringError::Generic(format!("{}", e))
}

pub(crate) fn map_log_err<T: std::error::Error>(e: T) -> T {
    error!("{}", e);
    e
}

cfg_if! {
    if #[cfg(test)] {
        mod tests;
    } else if #[cfg(feature="keyring_manager_android_tests")] {
        pub mod tests;
    } else if #[cfg(feature="keyring_manager_ios_tests")] {
        pub mod tests;
    }

}

mod error;
pub use error::{KeyringError, Result};