use std::borrow::Cow;
use super::defs::*;
use crate::account::v2::{Account, LogInError};
impl CommandProcessor {
pub(crate) fn authenticate_start(
&mut self,
cmd: &s::AuthenticateCommandStart<'_>,
) -> Option<s::ResponseLine<'static>> {
if "plain".eq_ignore_ascii_case(&cmd.auth_type) {
cmd.initial_response.as_ref().map(|ir| {
self.authenticate_finish(cmd.to_owned(), ir.as_bytes())
})
} else {
Some(s::ResponseLine {
tag: Some(Cow::Owned(cmd.tag.clone().into_owned())),
response: s::Response::Cond(s::CondResponse {
cond: s::RespCondType::Bad,
code: Some(s::RespTextCode::Cannot(())),
quip: Some(Cow::Borrowed("Unsupported AUTHENTICATE type")),
}),
})
}
}
pub(crate) fn authenticate_finish(
&mut self,
cmd: s::AuthenticateCommandStart<'_>,
data: &[u8],
) -> s::ResponseLine<'static> {
let tag = Cow::Owned(cmd.tag.into_owned());
if b"*" == data {
return s::ResponseLine {
tag: Some(tag),
response: s::Response::Cond(s::CondResponse {
cond: s::RespCondType::Bad,
code: None,
quip: Some(Cow::Borrowed("AUTHENTICATE aborted")),
}),
};
}
let string = match base64::decode(data)
.ok()
.and_then(|decoded| String::from_utf8(decoded).ok())
{
Some(s) => s,
None => {
return s::ResponseLine {
tag: Some(tag),
response: s::Response::Cond(s::CondResponse {
cond: s::RespCondType::Bad,
code: Some(s::RespTextCode::Parse(())),
quip: Some(Cow::Borrowed("Bad base64 or UTF-8")),
}),
}
},
};
let mut parts = string.split('\x00');
match (parts.next(), parts.next(), parts.next(), parts.next()) {
(Some(authorise), Some(authenticate), Some(password), None) => {
if !authorise.is_empty() && authorise != authenticate {
return s::ResponseLine {
tag: Some(tag),
response: s::Response::Cond(s::CondResponse {
cond: s::RespCondType::No,
code: Some(s::RespTextCode::Cannot(())),
quip: Some(Cow::Borrowed(
"AUTHENTICATE PLAIN with different \
authorising and authenticating users \
is not supported",
)),
}),
};
}
let r = self.cmd_log_in(s::LogInCommand {
userid: Cow::Borrowed(authenticate),
password: Cow::Borrowed(password),
});
let r = match r {
Ok(r) => r,
Err(r) => r,
};
s::ResponseLine {
tag: Some(tag),
response: r,
}
},
_ => s::ResponseLine {
tag: Some(tag),
response: s::Response::Cond(s::CondResponse {
cond: s::RespCondType::Bad,
code: Some(s::RespTextCode::Parse(())),
quip: Some(Cow::Borrowed(
"Malformed AUTHENTICATE PLAIN string",
)),
}),
},
}
}
pub(crate) fn cmd_log_in(&mut self, cmd: s::LogInCommand<'_>) -> CmdResult {
if self.account.is_some() {
return Err(s::Response::Cond(s::CondResponse {
cond: s::RespCondType::Bad,
code: Some(s::RespTextCode::ClientBug(())),
quip: Some(Cow::Borrowed("Already logged in")),
}));
}
match Account::log_in(
self.log_prefix.clone(),
&self.system_config,
&self.data_root,
&cmd.userid,
&cmd.password,
) {
Ok((account, _)) => {
self.account = Some(account);
Ok(s::Response::Cond(s::CondResponse {
cond: s::RespCondType::Ok,
code: Some(s::RespTextCode::Capability(
super::commands::capability_data(),
)),
quip: Some(Cow::Borrowed("User login successful")),
}))
},
Err(LogInError::IllegalUserId) => {
Err(s::Response::Cond(s::CondResponse {
cond: s::RespCondType::No,
code: Some(s::RespTextCode::AuthenticationFailed(())),
quip: Some(Cow::Borrowed("Illegal user id")),
}))
},
Err(LogInError::InvalidCredentials) => {
Err(s::Response::Cond(s::CondResponse {
cond: s::RespCondType::No,
code: Some(s::RespTextCode::AuthenticationFailed(())),
quip: Some(Cow::Borrowed("Bad user id or password")),
}))
},
Err(e @ LogInError::ConfigError) => {
Err(s::Response::Cond(s::CondResponse {
cond: s::RespCondType::Bye,
code: Some(s::RespTextCode::ContactAdmin(())),
quip: Some(Cow::Owned(e.to_string())),
}))
},
Err(e @ LogInError::SetupError) => {
Err(s::Response::Cond(s::CondResponse {
cond: s::RespCondType::No,
code: Some(s::RespTextCode::ContactAdmin(())),
quip: Some(Cow::Owned(e.to_string())),
}))
},
}
}
}