ncrypt_me/
credentials.rs

1use super::error::CredentialsError;
2use secure_types::SecureString;
3
4/// The credentials needed to encrypt and decrypt a file.
5///
6/// Credentials are erased from memory when they are dropped.
7///
8/// But they can also be erased manually by calling the [Credentials::erase()]
9#[derive(Clone)]
10pub struct Credentials {
11   pub username: SecureString,
12   pub password: SecureString,
13   pub confirm_password: SecureString,
14}
15
16impl Credentials {
17   pub fn new(
18      username: SecureString,
19      password: SecureString,
20      confirm_password: SecureString,
21   ) -> Self {
22      Self {
23         username,
24         password,
25         confirm_password,
26      }
27   }
28
29   /// Creates a new `Credentials` instance with the specified capacity.
30   pub fn new_with_capacity(capacity: usize) -> Result<Self, CredentialsError> {
31      let username = SecureString::new_with_capacity(capacity)
32         .map_err(|e| CredentialsError::Custom(e.to_string()))?;
33
34      let password = SecureString::new_with_capacity(capacity)
35         .map_err(|e| CredentialsError::Custom(e.to_string()))?;
36
37      let confirm_password = SecureString::new_with_capacity(capacity)
38         .map_err(|e| CredentialsError::Custom(e.to_string()))?;
39      Ok(Self {
40         username,
41         password,
42         confirm_password,
43      })
44   }
45
46   /// Erases the credentials from memory by zeroizing the username and password fields.
47   ///
48   /// This method is automatically called when the `Credentials` instance is dropped.
49   pub fn erase(&mut self) {
50      self.username.erase();
51      self.password.erase();
52      self.confirm_password.erase();
53   }
54
55   /// Copy password to confirm password
56   pub fn copy_passwd_to_confirm(&mut self) {
57      self.password.unlock_str(|str| {
58         self.confirm_password.erase();
59         self.confirm_password.push_str(str);
60      });
61   }
62
63   pub fn is_valid(&self) -> Result<(), CredentialsError> {
64      if self.username.char_len() == 0 {
65         return Err(CredentialsError::UsernameEmpty);
66      }
67
68      if self.password.char_len() == 0 {
69         return Err(CredentialsError::PasswordEmpty);
70      }
71
72      if self.confirm_password.char_len() == 0 {
73         return Err(CredentialsError::ConfirmPasswordEmpty);
74      }
75
76      let res = self.password.unlock_str(|password| {
77         self.confirm_password.unlock_str(|confirm_password| {
78            if password != confirm_password {
79               return Err(CredentialsError::PasswordsDoNotMatch);
80            } else {
81               Ok(())
82            }
83         })
84      });
85      res
86   }
87}
88
89impl Default for Credentials {
90   fn default() -> Self {
91      Self::new(
92         SecureString::from(""),
93         SecureString::from(""),
94         SecureString::from(""),
95      )
96   }
97}
98
99#[cfg(test)]
100mod tests {
101   use super::*;
102
103   #[test]
104   fn test_copy_passwd_to_confirm() {
105      let mut credentials = Credentials::new(
106         SecureString::from("username"),
107         SecureString::from("password"),
108         SecureString::from("something_else"),
109      );
110
111      credentials.copy_passwd_to_confirm();
112      assert!(credentials.is_valid().is_ok());
113   }
114}