use crate::sync::{AuthDb, PgUser}; use bcrypt::verify; pub struct SftpAuth { auth_db: AuthDb, } impl SftpAuth { pub fn new(auth_db_path: &str) -> anyhow::Result { let auth_db = AuthDb::new(auth_db_path)?; Ok(Self { auth_db }) } pub fn verify_password(&self, username: &str, password: &str) -> bool { match self.auth_db.get_user(username) { Ok(Some(user)) if user.status == 1 => { verify(password, &user.password_hash).unwrap_or(false) } Ok(Some(_)) => { log::warn!("User {} is disabled", username); false } Ok(None) => { log::warn!("User {} not found", username); false } Err(e) => { log::error!("Failed to get user {}: {}", username, e); false } } } pub fn get_user(&self, username: &str) -> Option { self.auth_db.get_user(username).ok().flatten() } } #[cfg(test)] mod tests { use bcrypt::{hash, verify, DEFAULT_COST}; #[test] fn test_bcrypt_verify_correct_password() { let password = "demo123"; let hashed = hash(password, DEFAULT_COST).unwrap(); // 验证正确密码 let valid = verify(password, &hashed).unwrap(); assert!(valid); } #[test] fn test_bcrypt_verify_wrong_password() { let password = "demo123"; let wrong_password = "wrong123"; let hashed = hash(password, DEFAULT_COST).unwrap(); // 验证错误密码 let valid = verify(wrong_password, &hashed).unwrap(); assert!(!valid); } #[test] fn test_bcrypt_verify_empty_password() { let password = ""; let hashed = hash(password, DEFAULT_COST).unwrap(); // 验证空密码 let valid = verify(password, &hashed).unwrap(); assert!(valid); // 验证非空密码对空hash let valid = verify("test", &hashed).unwrap(); assert!(!valid); } #[test] fn test_verify_database_hash() { // 验证数据库中的实际hash(demo123) let db_hash = "$2b$10$ha5wU.mOi8fHLJCfun860u2cfVopa04jwe/q82IKOwqp5uG70qsH6"; let password = "demo123"; let valid = verify(password, db_hash).unwrap(); assert!(valid); } }