use crate::server::chancomms::InternalMsg;
use crate::server::commands::Cmd;
use crate::server::error::FTPError;
use crate::server::password;
use crate::server::reply::{Reply, ReplyCode};
use crate::server::session::SessionState;
use crate::server::CommandArgs;
use crate::storage;
use futures::future::Future;
use futures::sink::Sink;
use std::sync::Arc;
pub struct Pass {
password: password::Password,
}
impl Pass {
pub fn new(password: password::Password) -> Self {
Pass { password }
}
}
impl<S, U> Cmd<S, U> for Pass
where
U: Send + Sync + 'static,
S: 'static + storage::StorageBackend<U> + Sync + Send,
S::File: tokio_io::AsyncRead + Send,
S::Metadata: storage::Metadata,
{
fn execute(&self, args: &CommandArgs<S, U>) -> Result<Reply, FTPError> {
let session_arc = args.session.clone();
let session = args.session.lock()?;
match &session.state {
SessionState::WaitPass => {
let pass = std::str::from_utf8(&self.password.as_ref())?;
let user = session.username.clone().unwrap();
let tx = args.tx.clone();
tokio::spawn(
args.authenticator
.authenticate(&user, pass)
.then(move |user| {
match user {
Ok(user) => {
let mut session = session_arc.lock().unwrap();
session.user = Arc::new(Some(user));
tx.send(InternalMsg::AuthSuccess)
}
_ => tx.send(InternalMsg::AuthFailed), }
})
.map(|_| ())
.map_err(|_| ()),
);
Ok(Reply::none())
}
SessionState::New => Ok(Reply::new(ReplyCode::BadCommandSequence, "Please supply a username first")),
_ => Ok(Reply::new(ReplyCode::NotLoggedIn, "Please open a new connection to re-authenticate")),
}
}
}