use crate::protocol::{AsyncStreamOperation, AuthMethod, UserKey, handshake::password_method};
use std::sync::Arc;
use tokio::net::TcpStream;
#[async_trait::async_trait]
pub trait AuthExecutor {
fn auth_method(&self) -> AuthMethod;
async fn execute(&self, stream: &mut TcpStream) -> std::io::Result<bool>;
}
pub type AuthAdaptor = Arc<dyn AuthExecutor + Send + Sync>;
#[derive(Debug, Default)]
pub struct NoAuth;
#[async_trait::async_trait]
impl AuthExecutor for NoAuth {
fn auth_method(&self) -> AuthMethod {
AuthMethod::NoAuth
}
async fn execute(&self, _: &mut TcpStream) -> std::io::Result<bool> {
Ok(true)
}
}
#[derive(Debug, Clone)]
pub struct UserKeyAuth {
user_key: UserKey,
}
impl From<UserKey> for UserKeyAuth {
fn from(user_key: UserKey) -> Self {
Self { user_key }
}
}
impl From<&UserKey> for UserKeyAuth {
fn from(value: &UserKey) -> Self {
Self { user_key: value.clone() }
}
}
impl From<(&str, &str)> for UserKeyAuth {
fn from(value: (&str, &str)) -> Self {
Self::new(value.0, value.1)
}
}
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 {
fn auth_method(&self) -> AuthMethod {
AuthMethod::UserPass
}
async fn execute(&self, stream: &mut TcpStream) -> std::io::Result<bool> {
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"))
}
}
}