Skip to main content

huawei_dongle_api/
auth.rs

1//! Authentication utilities and password encoding
2
3use crate::models::auth::{LoginState, PasswordEncoding};
4use base64::{engine::general_purpose, Engine as _};
5use sha2::{Digest, Sha256};
6
7/// Password encoder for different Huawei authentication types
8pub struct PasswordEncoder;
9
10impl PasswordEncoder {
11    /// Encode password based on the login state requirements
12    pub fn encode_password(password: &str, login_state: &LoginState) -> String {
13        match login_state.password_encoding() {
14            PasswordEncoding::Base64 | PasswordEncoding::Base64AfterChange => {
15                Self::encode_base64(password)
16            }
17            PasswordEncoding::Sha256 => Self::encode_sha256(password),
18            PasswordEncoding::Unknown => Self::encode_sha256(password),
19        }
20    }
21
22    /// Encode password using BASE64
23    fn encode_base64(password: &str) -> String {
24        general_purpose::STANDARD.encode(password.as_bytes())
25    }
26
27    /// Encode password using SHA256
28    fn encode_sha256(password: &str) -> String {
29        let mut hasher = Sha256::new();
30        hasher.update(password.as_bytes());
31        let result = hasher.finalize();
32        hex::encode(result)
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39    use crate::models::auth::LoginState;
40    use crate::models::{LockStatus, LoginStatus};
41
42    fn create_test_login_state(password_type: &str) -> LoginState {
43        LoginState {
44            password_type: password_type.to_string(),
45            state: LoginStatus::NotLoggedIn,
46            lock_status: LockStatus::Unlocked,
47            extern_password_type: "1".to_string(),
48            history_login_flag: "0".to_string(),
49            guide_modify_pwd_page_flag: "0".to_string(),
50            rsa_padding_type: "1".to_string(),
51            accounts_number: "1".to_string(),
52            wifi_pwd_same_with_web_pwd: "0".to_string(),
53            remain_wait_time: "0".to_string(),
54            force_skip_guide: "0".to_string(),
55            username: "".to_string(),
56            first_login: "0".to_string(),
57            user_level: "".to_string(),
58        }
59    }
60
61    #[test]
62    fn test_base64_encoding() {
63        let login_state = create_test_login_state("0");
64        let password = "admin";
65        let encoded = PasswordEncoder::encode_password(password, &login_state);
66        assert_eq!(encoded, "YWRtaW4=");
67    }
68
69    #[test]
70    fn test_sha256_encoding() {
71        let login_state = create_test_login_state("4");
72        let password = "admin";
73        let encoded = PasswordEncoder::encode_password(password, &login_state);
74
75        assert_eq!(encoded.len(), 64);
76        assert!(encoded.chars().all(|c| c.is_ascii_hexdigit()));
77        let expected = "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918";
78        assert_eq!(encoded, expected);
79    }
80
81    #[test]
82    fn test_unknown_type_defaults_to_sha256() {
83        let login_state = create_test_login_state("999"); // Unknown type
84        let password = "admin";
85        let encoded = PasswordEncoder::encode_password(password, &login_state);
86        assert_eq!(encoded.len(), 64);
87        let expected = "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918";
88        assert_eq!(encoded, expected);
89    }
90
91    #[test]
92    fn test_base64_after_change_encoding() {
93        let login_state = create_test_login_state("3");
94        let password = "newpassword";
95        let encoded = PasswordEncoder::encode_password(password, &login_state);
96        let expected = general_purpose::STANDARD.encode("newpassword".as_bytes());
97        assert_eq!(encoded, expected);
98    }
99}