use std::{
io,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use rcgen::generate_simple_self_signed;
use rustls::{ServerConfig as RustlsServerConfig, pki_types::PrivateKeyDer};
use tokio::{
io::{AsyncRead, AsyncWrite, ReadBuf},
net::TcpStream,
};
use tokio_rustls::{TlsAcceptor, server::TlsStream};
pub enum ImapStream {
Plain(TcpStream),
Tls(TlsStream<TcpStream>),
}
pub enum SmtpStream {
Plain(TcpStream),
Tls(TlsStream<TcpStream>),
}
impl AsyncRead for ImapStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<io::Result<()>> {
match self.get_mut() {
Self::Plain(stream) => Pin::new(stream).poll_read(cx, buf),
Self::Tls(stream) => Pin::new(stream).poll_read(cx, buf),
}
}
}
impl AsyncWrite for ImapStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
data: &[u8],
) -> Poll<io::Result<usize>> {
match self.get_mut() {
Self::Plain(stream) => Pin::new(stream).poll_write(cx, data),
Self::Tls(stream) => Pin::new(stream).poll_write(cx, data),
}
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match self.get_mut() {
Self::Plain(stream) => Pin::new(stream).poll_flush(cx),
Self::Tls(stream) => Pin::new(stream).poll_flush(cx),
}
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match self.get_mut() {
Self::Plain(stream) => Pin::new(stream).poll_shutdown(cx),
Self::Tls(stream) => Pin::new(stream).poll_shutdown(cx),
}
}
}
impl Unpin for ImapStream {}
impl AsyncRead for SmtpStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<io::Result<()>> {
match self.get_mut() {
Self::Plain(stream) => Pin::new(stream).poll_read(cx, buf),
Self::Tls(stream) => Pin::new(stream).poll_read(cx, buf),
}
}
}
impl AsyncWrite for SmtpStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
data: &[u8],
) -> Poll<io::Result<usize>> {
match self.get_mut() {
Self::Plain(stream) => Pin::new(stream).poll_write(cx, data),
Self::Tls(stream) => Pin::new(stream).poll_write(cx, data),
}
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match self.get_mut() {
Self::Plain(stream) => Pin::new(stream).poll_flush(cx),
Self::Tls(stream) => Pin::new(stream).poll_flush(cx),
}
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match self.get_mut() {
Self::Plain(stream) => Pin::new(stream).poll_shutdown(cx),
Self::Tls(stream) => Pin::new(stream).poll_shutdown(cx),
}
}
}
impl Unpin for SmtpStream {}
pub fn build_tls_acceptor() -> io::Result<TlsAcceptor> {
let rcgen::CertifiedKey { cert, key_pair } =
generate_simple_self_signed(vec!["localhost".to_string()]).map_err(io::Error::other)?;
let certs = vec![cert.der().clone()];
let key_der = key_pair.serialize_der();
let key = PrivateKeyDer::Pkcs8(key_der.into());
let config = RustlsServerConfig::builder_with_provider(Arc::new(
rustls::crypto::ring::default_provider(),
))
.with_safe_default_protocol_versions()
.map_err(io::Error::other)?
.with_no_client_auth()
.with_single_cert(certs, key)
.map_err(io::Error::other)?;
Ok(TlsAcceptor::from(Arc::new(config)))
}