dory/src/sender/mod.rs

132 lines
3.8 KiB
Rust

//! Sends a Misfin [`Request`]
use {
crate::prelude::{CertificateStore, ClientCertificateStore, Mailuser, Request, Response},
rustls::{ClientConfig, ClientConnection, StreamOwned},
std::{
io::{self, Read, Write},
net::{TcpStream, ToSocketAddrs},
sync::Arc,
time::Duration,
},
};
pub use self::{error::Error, verifier::Verifier};
mod error;
mod verifier;
#[derive(Debug)]
/// Sends a piece of mail from the sending server to the receiving server
pub struct Sender<S, C>
where
S: CertificateStore,
C: ClientCertificateStore,
{
/// The address of the sender
pub sender: Mailuser,
/// The full message text to be sent
pub request: Request,
/// A [CertificateStore] for servers known to us
pub store: S,
/// A [ClientCertificateStore] for mailboxes which exist on this system
pub client_store: C,
}
impl<S, C> Sender<S, C>
where
S: CertificateStore + 'static,
C: ClientCertificateStore,
{
pub fn new(sender: &str, request_str: &str, store: S, client_store: C) -> Result<Self, Error> {
let sender = sender.parse()?;
let request: Request = request_str.parse()?;
Ok(Self {
sender,
request,
store,
client_store,
})
}
fn host_string(&self) -> String {
self.request.recipient.host.to_string()
}
pub fn send(self) -> Result<Response, Error> {
let dnsname = self
.host_string()
.as_str()
.try_into()
.map_err(|_| Error::DnsError)?;
let mut it = self.request.recipient.host.to_socket_addrs()?;
let client_cert = self.client_store.get_certificate(&self.sender);
let verifier = Arc::new(Verifier::new(self.store));
let Some(socket_addrs) = it.next() else {
return Err(io::Error::new(io::ErrorKind::Other, "no data retrieved").into());
};
let tcp_stream = TcpStream::connect_timeout(&socket_addrs, Duration::new(10, 0))?;
let cfg = ClientConfig::builder()
.with_safe_defaults()
.with_custom_certificate_verifier(verifier);
let cfg = match client_cert {
None => cfg.with_no_client_auth(),
Some(c) => {
//let rustls_cert = rustls::Certificate::read_bytes(&c.der)?;
let rustls_cert = rustls::Certificate(c.der);
let cert_chain = vec![rustls_cert];
let key_der = rustls::PrivateKey(c.key);
cfg.with_single_cert(cert_chain, key_der)?
}
};
let client = ClientConnection::new(Arc::new(cfg), dnsname)?;
let mut stream = StreamOwned::new(client, tcp_stream);
stream.write_all(self.request.to_string().as_bytes())?;
let mut buf = Vec::with_capacity(1024);
let _res = stream.read_to_end(&mut buf);
stream.conn.send_close_notify();
drop(stream);
let res = buf.try_into()?;
Ok(res)
}
}
#[derive(Debug)]
pub struct MultiSender<S, C>
where
S: CertificateStore,
C: ClientCertificateStore,
{
pub sender: Mailuser,
pub recipients: Vec<Mailuser>,
pub store: S,
pub client_store: C,
}
impl<S, C> MultiSender<S, C>
where
S: CertificateStore + 'static + Clone,
C: ClientCertificateStore + Clone,
{
pub fn new(
sender: &str,
recipients: &[&str],
store: S,
client_store: C,
) -> Result<Self, Error> {
let mut rec = vec![];
for r in recipients {
let r = r.parse()?;
rec.push(r);
}
Ok(Self {
sender: sender.parse()?,
recipients: rec,
store,
client_store,
})
}
pub fn send(&self, f: &dyn Fn(Result<Response, Error>)) -> Result<(), Error> {
todo!()
}
}