remoteit_api/
credentials.rs

1//! This module is related to loading remote.it credentials from the user's home directory.
2//! This is of course not the most secure way to store credentials, but it is the most convenient and recommended by remote.it.
3//! If you store your credentials in a different way, you can pass them to the functions in this module directly instead of using this module to load them.
4
5use base64::prelude::BASE64_STANDARD;
6use base64::Engine;
7use bon::bon;
8
9/// Credentials for the remote.it API.
10/// Remote.it credentials consist of an access key ID and a base64 encoded secret access key.
11///
12/// # Example
13/// You can directly create a new [`Credentials`] struct using the builder pattern:
14/// ```
15/// # use remoteit_api::Credentials;
16/// let credentials = Credentials::builder()
17///     .r3_access_key_id("foo".to_owned())
18///     .r3_secret_access_key("YmFy".to_owned())
19///     .build();
20/// ```
21/// If you enable the `credentials_loader` feature, you can also load the credentials from the default, or a custom file:
22/// ```
23/// # use std::path::PathBuf;
24/// # use remoteit_api::Credentials;
25/// let creds_from_default_loc = Credentials::load_from_disk().call().unwrap();
26/// let creds_from_custom_loc = Credentials::load_from_disk().custom_credentials_path(PathBuf::from(".env.remoteit")).call().unwrap();
27/// ```
28#[derive(
29    Debug, Clone, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize,
30)]
31pub struct Credentials {
32    r3_access_key_id: String,
33    r3_secret_access_key: String,
34    #[serde(skip)] // Don't want to serialize this one
35    key: Vec<u8>,
36}
37
38#[bon]
39impl Credentials {
40    /// Validated the given secret access key and creates a new [`Credentials`] struct.
41    ///
42    /// # Errors
43    /// - [`base64::DecodeError`] if the secret access key is not base64 encoded.
44    ///
45    /// # Example
46    /// ```
47    /// # use remoteit_api::Credentials;
48    /// let credentials = Credentials::builder()
49    ///     .r3_access_key_id("foo".to_owned())
50    ///     .r3_secret_access_key("YmFy".to_owned())
51    ///     .build();
52    /// ```
53    #[builder]
54    pub fn new(
55        r3_access_key_id: String,
56        r3_secret_access_key: String,
57    ) -> Result<Self, base64::DecodeError> {
58        let key = BASE64_STANDARD.decode(&r3_secret_access_key)?;
59        Ok(Self {
60            r3_access_key_id,
61            r3_secret_access_key,
62            key,
63        })
64    }
65
66    /// # Returns
67    /// The base64 decoded secret access key.
68    #[must_use]
69    pub fn key(&self) -> &[u8] {
70        &self.key
71    }
72
73    /// # Returns
74    /// A reference to the r3_access_key_id
75    #[allow(clippy::must_use_candidate)]
76    pub fn access_key_id(&self) -> &str {
77        &self.r3_access_key_id
78    }
79
80    /// # Returns
81    /// The base64 encoded r3_secret_access_key
82    #[allow(clippy::must_use_candidate)]
83    pub fn secret_access_key(&self) -> &str {
84        &self.r3_secret_access_key
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn test_credentials_builder() {
94        let credentials = Credentials::builder()
95            .r3_access_key_id("foo".to_owned())
96            .r3_secret_access_key("YmFy".to_owned())
97            .build()
98            .unwrap();
99
100        assert_eq!(credentials.r3_access_key_id, "foo");
101        assert_eq!(credentials.r3_secret_access_key, "YmFy");
102    }
103
104    #[test]
105    fn test_get_key() {
106        let key = vec![1, 2, 3, 4];
107        let credentials = Credentials::builder()
108            .r3_access_key_id(String::new())
109            .r3_secret_access_key(BASE64_STANDARD.encode(&key))
110            .build()
111            .unwrap();
112
113        assert_eq!(key.as_slice(), credentials.key());
114    }
115
116    #[test]
117    fn test_get_access_key_id() {
118        let credentials = Credentials::builder()
119            .r3_access_key_id("foo".to_string())
120            .r3_secret_access_key("YmFy".to_owned())
121            .build()
122            .unwrap();
123
124        assert_eq!("foo", credentials.access_key_id());
125    }
126
127    #[test]
128    fn test_get_secret_access_key() {
129        let credentials = Credentials::builder()
130            .r3_access_key_id(String::new())
131            .r3_secret_access_key("YmFy".to_owned())
132            .build()
133            .unwrap();
134
135        assert_eq!(credentials.secret_access_key(), "YmFy");
136    }
137}