use crate::protocol::{AsyncStreamOperation, AuthMethod, UserKey, handshake::password_method};
use std::sync::Arc;
use tokio::net::TcpStream;
#[async_trait::async_trait]
pub trait AuthExecutor {
type Output;
fn auth_method(&self) -> AuthMethod;
async fn execute(&self, stream: &mut TcpStream) -> Self::Output;
}
pub type AuthAdaptor<O> = Arc<dyn AuthExecutor<Output = O> + Send + Sync>;
#[derive(Debug, Default)]
pub struct NoAuth;
#[async_trait::async_trait]
impl AuthExecutor for NoAuth {
type Output = ();
fn auth_method(&self) -> AuthMethod {
AuthMethod::NoAuth
}
async fn execute(&self, _: &mut TcpStream) -> Self::Output {}
}
pub struct UserKeyAuth {
user_key: UserKey,
}
impl UserKeyAuth {
pub fn new(username: &str, password: &str) -> Self {
let user_key = UserKey::new(username, password);
Self { user_key }
}
}
#[async_trait::async_trait]
impl AuthExecutor for UserKeyAuth {
type Output = std::io::Result<bool>;
fn auth_method(&self) -> AuthMethod {
AuthMethod::UserPass
}
async fn execute(&self, stream: &mut TcpStream) -> Self::Output {
use password_method::{Request, Response, Status::*};
let req = Request::retrieve_from_async_stream(stream).await?;
let is_equal = req.user_key == self.user_key;
let resp = Response::new(if is_equal { Succeeded } else { Failed });
resp.write_to_async_stream(stream).await?;
if is_equal {
Ok(true)
} else {
Err(std::io::Error::other("username or password is incorrect"))
}
}
}