use crate::protocol::{handshake::password_method, AuthMethod, UserKey};
use async_trait::async_trait;
use tokio::net::TcpStream;
#[async_trait]
pub trait AuthExecutor {
fn auth_method(&self) -> AuthMethod;
async fn execute(&self, stream: &mut TcpStream) -> std::io::Result<()>;
}
#[derive(Debug, Default)]
pub struct NoAuth;
#[async_trait]
impl AuthExecutor for NoAuth {
fn auth_method(&self) -> AuthMethod {
AuthMethod::NoAuth
}
async fn execute(&self, _: &mut TcpStream) -> std::io::Result<()> {
Ok(())
}
}
pub struct PasswordAuth {
user_key: UserKey,
}
impl PasswordAuth {
pub fn new(username: &str, password: &str) -> Self {
let user_key = UserKey::new(username, password);
Self { user_key }
}
}
#[async_trait]
impl AuthExecutor for PasswordAuth {
fn auth_method(&self) -> AuthMethod {
AuthMethod::UserPass
}
async fn execute(&self, stream: &mut TcpStream) -> std::io::Result<()> {
let req = password_method::Request::rebuild_from_stream(stream).await?;
if req.user_key == self.user_key {
let resp = password_method::Response::new(true);
resp.write_to_stream(stream).await?;
Ok(())
} else {
let resp = password_method::Response::new(false);
resp.write_to_stream(stream).await?;
let err = "SOCKS5 username / password authentication failed";
Err(std::io::Error::new(std::io::ErrorKind::InvalidData, err))
}
}
}