use async_trait::async_trait;
use socks5_proto::handshake::{
password::{Error as PasswordError, Request as PasswordRequest, Response as PasswordResponse},
Method,
};
use tokio::net::TcpStream;
#[async_trait]
pub trait Auth {
type Output;
fn as_handshake_method(&self) -> Method;
async fn execute(&self, stream: &mut TcpStream) -> Self::Output;
}
#[derive(Clone, Copy, Debug, Default)]
pub struct NoAuth;
impl NoAuth {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl Auth for NoAuth {
type Output = ();
fn as_handshake_method(&self) -> Method {
Method::NONE
}
async fn execute(&self, _: &mut TcpStream) -> Self::Output {}
}
#[derive(Clone, Debug)]
pub struct Password {
pub username: Vec<u8>,
pub password: Vec<u8>,
}
impl Password {
pub fn new(username: Vec<u8>, password: Vec<u8>) -> Self {
Self { username, password }
}
}
#[async_trait]
impl Auth for Password {
type Output = Result<bool, PasswordError>;
fn as_handshake_method(&self) -> Method {
Method::PASSWORD
}
async fn execute(&self, stream: &mut TcpStream) -> Self::Output {
let req = PasswordRequest::read_from(stream).await?;
if (&req.username, &req.password) == (&self.username, &self.password) {
let resp = PasswordResponse::new(true);
resp.write_to(stream).await?;
Ok(true)
} else {
let resp = PasswordResponse::new(false);
resp.write_to(stream).await?;
Ok(false)
}
}
}