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
120
121
122
123
124
125
use std::path::Path;
use credent_fs_model::{AppName, Error};
use credent_model::{Profile, Profiles};
use crate::CredentialsFile;
/// Reads credentials from the user's configuration directory.
#[derive(Debug)]
pub struct CredentialsFileLoader;
impl CredentialsFileLoader {
/// Returns the default profile credentials stored in the user's
/// configuration directory.
///
/// The path differs depending on the user's operating system:
///
/// * `Windows`: `C:\Users\%USER%\AppData\Roaming\<app>\credentials`
/// * `Linux`: `$XDG_CONFIG_HOME` or `$HOME/.config/<app>/credentials`
/// * `OS X`: `$HOME/Library/Application Support/<app>/credentials`
///
/// # Parameters
///
/// * `app_name`: Name of the application whose credentials to load.
pub async fn load(app_name: AppName<'_>) -> Result<Option<Profile>, Error> {
let credentials_path = CredentialsFile::path(app_name)?;
if credentials_path.exists() {
Self::load_profile(app_name, Profile::DEFAULT_NAME).await
} else {
Ok(None)
}
}
/// Returns the profile credentials stored in the user's configuration
/// directory.
///
/// The path differs depending on the user's operating system:
///
/// * `Windows`: `C:\Users\%USER%\AppData\Roaming\<app>\credentials`
/// * `Linux`: `$XDG_CONFIG_HOME` or `$HOME/.config/<app>/credentials`
/// * `OS X`: `$HOME/Library/Application Support/<app>/credentials`
///
/// # Parameters
///
/// * `app_name`: Name of the application whose credentials to load.
/// * `profile_name`: Which profile's credentials to load.
pub async fn load_profile(
app_name: AppName<'_>,
profile_name: &str,
) -> Result<Option<Profile>, Error> {
Self::load_all(app_name)
.await
.map(|profiles_result| {
profiles_result.map(|profiles| {
profiles
.0
.into_iter()
.find(|profile| profile.name == profile_name)
})
})
.map(Option::flatten)
}
/// Returns all profile credentials stored in the user's configuration
/// directory.
///
/// The path differs depending on the user's operating system:
///
/// * `Windows`: `C:\Users\%USER%\AppData\Roaming\<app>\credentials`
/// * `Linux`: `$XDG_CONFIG_HOME` or `$HOME/.config/<app>/credentials`
/// * `OS X`: `$HOME/Library/Application Support/<app>/credentials`
///
/// # Parameters
///
/// * `app_name`: Name of the application whose credentials to load.
pub async fn load_all(app_name: AppName<'_>) -> Result<Option<Profiles>, Error> {
let credentials_path = CredentialsFile::path(app_name)?;
if credentials_path.exists() {
Self::load_file(credentials_path.as_ref()).await.map(Some)
} else {
Ok(None)
}
}
/// Loads all credential profiles from the given file.
///
/// # Parameters
///
/// * `credentials_path`: File to load credentials from.
pub async fn load_file(credentials_path: &Path) -> Result<Profiles, Error> {
if !credentials_path.exists() {
let credentials_path = credentials_path.to_owned();
Err(Error::CredentialsFileNonExistent { credentials_path })
} else if credentials_path.is_dir() {
let credentials_path = credentials_path.to_owned();
Err(Error::CredentialsFileIsDir { credentials_path })
} else {
let profiles_contents = Self::credentials_file_read(credentials_path).await?;
Self::credentials_deserialize(profiles_contents, credentials_path)
}
}
async fn credentials_file_read(credentials_path: &Path) -> Result<Vec<u8>, Error> {
async_fs::read(credentials_path).await.map_err(|io_error| {
let credentials_path = credentials_path.to_owned();
Error::CredentialsFileFailedToRead {
credentials_path,
io_error,
}
})
}
fn credentials_deserialize(
profiles_contents: Vec<u8>,
credentials_path: &Path,
) -> Result<Profiles, Error> {
toml::from_slice(&profiles_contents).map_err(|toml_de_error| {
let credentials_path = credentials_path.to_owned();
Error::CredentialsFileFailedToDeserialize {
credentials_path,
toml_de_error,
}
})
}
}