Flesh out most of sender
functionality
This commit is contained in:
parent
887ab8e085
commit
680ca4e9b9
5 changed files with 69 additions and 22 deletions
|
@ -1,4 +1,8 @@
|
||||||
use std::{fmt, str::FromStr};
|
use std::{
|
||||||
|
fmt,
|
||||||
|
net::{SocketAddr, ToSocketAddrs},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
mod error;
|
mod error;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
|
||||||
|
@ -72,6 +76,14 @@ impl FromStr for Host {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToSocketAddrs for Host {
|
||||||
|
type Iter = std::vec::IntoIter<SocketAddr>;
|
||||||
|
|
||||||
|
fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
|
||||||
|
format!("{}:1958", self).to_socket_addrs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -6,6 +6,7 @@ use {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Errors which might occur when sending a message
|
/// Errors which might occur when sending a message
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
DnsError,
|
||||||
TlsError(rustls::Error),
|
TlsError(rustls::Error),
|
||||||
RequestError(ParseRequestError),
|
RequestError(ParseRequestError),
|
||||||
ResponseError(ParseResponseError),
|
ResponseError(ParseResponseError),
|
||||||
|
@ -15,6 +16,7 @@ pub enum Error {
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
Self::DnsError => write!(f, "Dns Error"),
|
||||||
Self::TlsError(e) => write!(f, "{e}"),
|
Self::TlsError(e) => write!(f, "{e}"),
|
||||||
Self::RequestError(e) => write!(f, "{e}"),
|
Self::RequestError(e) => write!(f, "{e}"),
|
||||||
Self::ResponseError(e) => write!(f, "{e}"),
|
Self::ResponseError(e) => write!(f, "{e}"),
|
||||||
|
@ -26,6 +28,7 @@ impl fmt::Display for Error {
|
||||||
impl std::error::Error for Error {
|
impl std::error::Error for Error {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
|
Self::DnsError => None,
|
||||||
Self::RequestError(e) => Some(e),
|
Self::RequestError(e) => Some(e),
|
||||||
Self::ResponseError(e) => Some(e),
|
Self::ResponseError(e) => Some(e),
|
||||||
Self::TlsError(e) => Some(e),
|
Self::TlsError(e) => Some(e),
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
|
use std::{
|
||||||
|
io,
|
||||||
|
net::{TcpStream, ToSocketAddrs},
|
||||||
|
sync::Arc,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use rustls::{ClientConfig, ClientConnection, StreamOwned};
|
||||||
|
|
||||||
pub use self::{error::Error, verifier::Verifier};
|
pub use self::{error::Error, verifier::Verifier};
|
||||||
use {
|
use {
|
||||||
crate::prelude::{CertificateStore, Request, Response},
|
crate::prelude::{CertificateStore, Request},
|
||||||
std::io::{Read, Write},
|
std::io::{Read, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,33 +18,56 @@ mod verifier;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Sends a piece of mail from the sending server to the receiving server
|
/// Sends a piece of mail from the sending server to the receiving server
|
||||||
pub struct Sender<S, C, T>
|
pub struct Sender<S>
|
||||||
where
|
where
|
||||||
S: CertificateStore,
|
S: CertificateStore,
|
||||||
C: Sized,
|
|
||||||
T: Read + Write + Sized,
|
|
||||||
{
|
{
|
||||||
/// The full message text to be sent
|
/// The full message text to be sent
|
||||||
pub request: Request,
|
pub request: Request,
|
||||||
/// Verifies the receiving server's certificate
|
/// A [CertificateStore] for servers known to us
|
||||||
pub verifier: Verifier<S>,
|
pub store: S,
|
||||||
/// The TLS stream used for the connection
|
/// A [CertificateStore] for mailboxes which exist on this system
|
||||||
pub stream: rustls::StreamOwned<C, T>,
|
pub client_store: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, C, T> Sender<S, C, T>
|
impl<S> Sender<S>
|
||||||
where
|
where
|
||||||
S: CertificateStore,
|
S: CertificateStore + 'static
|
||||||
C: Sized,
|
|
||||||
T: Read + Write + Sized,
|
|
||||||
{
|
{
|
||||||
pub fn new(request_str: &str, store: S) -> Result<Self, Error> {
|
pub fn new(request_str: &str, store: S, client_store: S) -> Result<Self, Error> {
|
||||||
let request: Request = request_str.parse()?;
|
let request: Request = request_str.parse()?;
|
||||||
let verifier = Verifier::new(store);
|
Ok(Self { request, store, client_store })
|
||||||
unimplemented!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(&mut self) -> Result<Response, Error> {
|
fn host_string(&self) -> String {
|
||||||
unimplemented!();
|
self.request.sender.host.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(self) -> Result<Vec<u8>, Error> {
|
||||||
|
let dnsname = self
|
||||||
|
.host_string()
|
||||||
|
.as_str()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| Error::DnsError)?;
|
||||||
|
let mut it = self.request.sender.host.to_socket_addrs()?;
|
||||||
|
let client_cert = self.client_store.get_certificate(&self.request.sender.to_string());
|
||||||
|
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(_) => cfg.with_no_client_auth(),// todo: 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![];
|
||||||
|
stream.read_to_end(&mut buf)?;
|
||||||
|
Ok(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use {
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
borrow::BorrowMut,
|
borrow::BorrowMut,
|
||||||
sync::{Arc, Mutex},
|
sync::Mutex,
|
||||||
time,
|
time,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,7 @@ use {
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Verifier<S: CertificateStore> {
|
pub struct Verifier<S: CertificateStore> {
|
||||||
/// An item which serves as storage for certificates
|
/// An item which serves as storage for certificates
|
||||||
pub store: Arc<Mutex<S>>,
|
pub store: Mutex<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: CertificateStore> ServerCertVerifier for Verifier<S> {
|
impl<S: CertificateStore> ServerCertVerifier for Verifier<S> {
|
||||||
|
@ -82,7 +82,7 @@ impl<S: CertificateStore> ServerCertVerifier for Verifier<S> {
|
||||||
impl<T: CertificateStore> From<T> for Verifier<T> {
|
impl<T: CertificateStore> From<T> for Verifier<T> {
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
store: Arc::new(Mutex::new(value)),
|
store: Mutex::new(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue