use crate::alloc::string::String;
use crate::context::{Demand, DemandReply, Provider};
use crate::error::MechanismErrorKind;
use crate::mechanism::{Authentication, MechanismError};
use crate::prelude::SessionError;
use crate::property::{AuthId, Password};
use crate::session::{MechanismData, MessageSent, State};
use core::str::Utf8Error;
use crate::io::Write;
use thiserror::Error;
#[derive(Debug, Error)]
enum LoginError {
#[error(transparent)]
Utf8(Utf8Error),
}
impl MechanismError for LoginError {
fn kind(&self) -> MechanismErrorKind {
MechanismErrorKind::Parse
}
}
#[derive(Debug)]
pub struct Login {
state: LoginState,
}
#[derive(Debug, Eq, PartialEq)]
enum LoginState {
New,
WaitingForUsername,
WaitingForPassword(String),
Done,
}
impl Login {
pub const fn new() -> Self {
Self {
state: LoginState::New,
}
}
}
impl Authentication for Login {
fn step(
&mut self,
session: &mut MechanismData,
input: Option<&[u8]>,
writer: &mut dyn Write,
) -> Result<State, SessionError> {
match self.state {
LoginState::New => {
let out = b"User Name\0";
writer.write_all(out)?;
self.state = LoginState::WaitingForUsername;
Ok(State::Running)
}
LoginState::WaitingForUsername => {
if let Some(input) = input {
let username = core::str::from_utf8(input)
.map_err(LoginError::Utf8)?
.to_string();
let out = b"Password\0";
writer.write_all(out)?;
self.state = LoginState::WaitingForPassword(username);
Ok(State::Running)
} else {
Err(SessionError::InputDataRequired)
}
}
LoginState::WaitingForPassword(ref username) => {
if let Some(input) = input {
struct LoginProvider<'a> {
authid: &'a str,
password: &'a [u8],
}
impl<'a> Provider<'a> for LoginProvider<'a> {
fn provide(&self, req: &mut Demand<'a>) -> DemandReply<()> {
req.provide_ref::<AuthId>(self.authid)?
.provide_ref::<Password>(self.password)?
.done()
}
}
let prov = LoginProvider {
authid: username.as_str(),
password: input,
};
session.validate(&prov)?;
self.state = LoginState::Done;
Ok(State::Finished(MessageSent::No))
} else {
Err(SessionError::InputDataRequired)
}
}
LoginState::Done => Err(SessionError::MechanismDone),
}
}
}