aerogramme/src/imap/command/anonymous.rs

84 lines
2.7 KiB
Rust
Raw Normal View History

use anyhow::Result;
2024-01-01 08:34:13 +00:00
use imap_codec::imap_types::command::{Command, CommandBody};
2024-01-02 19:23:33 +00:00
use imap_codec::imap_types::core::AString;
2024-01-03 11:29:19 +00:00
use imap_codec::imap_types::response::Code;
use imap_codec::imap_types::secret::Secret;
2022-06-20 16:09:20 +00:00
2024-01-03 14:00:05 +00:00
use crate::imap::capability::ServerCapability;
2024-01-01 18:25:28 +00:00
use crate::imap::command::anystate;
2022-06-20 16:09:20 +00:00
use crate::imap::flow;
use crate::imap::response::Response;
2022-06-29 10:50:44 +00:00
use crate::login::ArcLoginProvider;
2022-06-29 11:41:05 +00:00
use crate::mail::user::User;
2022-06-17 16:39:36 +00:00
//--- dispatching
2022-06-29 10:50:44 +00:00
pub struct AnonymousContext<'a> {
2024-01-02 19:23:33 +00:00
pub req: &'a Command<'static>,
2024-01-03 11:29:19 +00:00
pub server_capabilities: &'a ServerCapability,
pub login_provider: &'a ArcLoginProvider,
2022-06-29 10:50:44 +00:00
}
2024-01-02 19:23:33 +00:00
pub async fn dispatch(ctx: AnonymousContext<'_>) -> Result<(Response<'static>, flow::Transition)> {
2024-01-01 08:34:13 +00:00
match &ctx.req.body {
2024-01-01 18:25:28 +00:00
// Any State
CommandBody::Noop => anystate::noop_nothing(ctx.req.tag.clone()),
2024-01-03 14:00:05 +00:00
CommandBody::Capability => {
anystate::capability(ctx.req.tag.clone(), ctx.server_capabilities)
}
2024-01-02 19:23:33 +00:00
CommandBody::Logout => anystate::logout(),
2024-01-01 18:25:28 +00:00
// Specific to anonymous context (3 commands)
2022-06-29 10:50:44 +00:00
CommandBody::Login { username, password } => ctx.login(username, password).await,
2024-01-01 18:25:28 +00:00
CommandBody::Authenticate { .. } => {
anystate::not_implemented(ctx.req.tag.clone(), "authenticate")
2023-12-29 16:16:41 +00:00
}
2024-01-01 18:25:28 +00:00
//StartTLS is not implemented for now, we will probably go full TLS.
// Collect other commands
_ => anystate::wrong_state(ctx.req.tag.clone()),
2022-06-17 16:39:36 +00:00
}
}
2022-06-20 16:09:20 +00:00
//--- Command controllers, private
2022-06-17 16:39:36 +00:00
2022-06-29 10:50:44 +00:00
impl<'a> AnonymousContext<'a> {
async fn login(
self,
username: &AString<'a>,
password: &Secret<AString<'a>>,
2024-01-02 19:23:33 +00:00
) -> Result<(Response<'static>, flow::Transition)> {
2022-06-29 10:50:44 +00:00
let (u, p) = (
std::str::from_utf8(username.as_ref())?,
std::str::from_utf8(password.declassify().as_ref())?,
2022-06-29 10:50:44 +00:00
);
tracing::info!(user = %u, "command.login");
2022-06-17 16:39:36 +00:00
let creds = match self.login_provider.login(&u, &p).await {
2022-06-29 10:50:44 +00:00
Err(e) => {
tracing::debug!(error=%e, "authentication failed");
return Ok((
2024-01-02 14:35:23 +00:00
Response::build()
.to_req(self.req)
.message("Authentication failed")
2024-01-02 14:35:23 +00:00
.no()?,
2022-06-29 10:50:44 +00:00
flow::Transition::None,
));
}
Ok(c) => c,
};
2022-06-17 16:39:36 +00:00
let user = User::new(u.to_string(), creds).await?;
2022-06-29 10:50:44 +00:00
tracing::info!(username=%u, "connected");
Ok((
2024-01-02 14:35:23 +00:00
Response::build()
.to_req(self.req)
2024-01-03 11:29:19 +00:00
.code(Code::Capability(self.server_capabilities.to_vec()))
.message("Completed")
2024-01-02 14:35:23 +00:00
.ok()?,
2022-06-29 10:50:44 +00:00
flow::Transition::Authenticate(user),
))
}
2022-06-28 13:38:06 +00:00
}