Only expose one error type in crate root
This commit is contained in:
parent
34796c90d4
commit
84511b54a0
6 changed files with 40 additions and 55 deletions
|
|
@ -7,6 +7,10 @@ XXXX-YY-ZZ RELEASER <admin@example.com>
|
|||
which was not used and has been completely removed (!418)
|
||||
- `ProtocolError` and `AuthError` are no longer exported in crate root;
|
||||
access them from `error` module (!423)
|
||||
- `connect::ServerConnector` no longer has `Error` associated type, the methods return tokio_xmpp::Error directly,
|
||||
where Connection variant contains any error type that implements connect::ServerConnectorError (!421)
|
||||
- `starttls::Error` no longer has `TokioXMPP` variant ; only tokio_xmpp::Error can contain starttls::Error,
|
||||
not the other way around (!421)
|
||||
|
||||
Version 4.0.0:
|
||||
2024-07-26 Maxime “pep” Buquet <pep@bouah.net>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use tokio::io::{AsyncRead, AsyncWrite};
|
|||
use xmpp_parsers::jid::Jid;
|
||||
|
||||
use crate::xmpp_stream::XMPPStream;
|
||||
use crate::Error;
|
||||
|
||||
/// trait returned wrapped in XMPPStream by ServerConnector
|
||||
pub trait AsyncReadAndWrite: AsyncRead + AsyncWrite + Unpin + Send {}
|
||||
|
|
@ -17,19 +18,17 @@ pub trait ServerConnectorError: std::error::Error + Sync + Send {}
|
|||
pub trait ServerConnector: Clone + core::fmt::Debug + Send + Unpin + 'static {
|
||||
/// The type of Stream this ServerConnector produces
|
||||
type Stream: AsyncReadAndWrite;
|
||||
/// Error type to return
|
||||
type Error: ServerConnectorError;
|
||||
/// This must return the connection ready to login, ie if starttls is involved, after TLS has been started, and then after the <stream headers are exchanged
|
||||
fn connect(
|
||||
&self,
|
||||
jid: &Jid,
|
||||
ns: &str,
|
||||
) -> impl std::future::Future<Output = Result<XMPPStream<Self::Stream>, Self::Error>> + Send;
|
||||
) -> impl std::future::Future<Output = Result<XMPPStream<Self::Stream>, Error>> + Send;
|
||||
|
||||
/// Return channel binding data if available
|
||||
/// do not fail if channel binding is simply unavailable, just return Ok(None)
|
||||
/// this should only be called after the TLS handshake is finished
|
||||
fn channel_binding(_stream: &Self::Stream) -> Result<ChannelBinding, Self::Error> {
|
||||
fn channel_binding(_stream: &Self::Stream) -> Result<ChannelBinding, Error> {
|
||||
Ok(ChannelBinding::None)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ use tokio_rustls::rustls::pki_types::InvalidDnsNameError;
|
|||
#[cfg(all(feature = "tls-rust", not(feature = "tls-native")))]
|
||||
use tokio_rustls::rustls::Error as TlsError;
|
||||
|
||||
use super::ServerConnectorError;
|
||||
|
||||
/// StartTLS ServerConnector Error
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
|
@ -25,41 +27,34 @@ pub enum Error {
|
|||
#[cfg(all(feature = "tls-rust", not(feature = "tls-native")))]
|
||||
/// DNS name parsing error
|
||||
DnsNameError(InvalidDnsNameError),
|
||||
/// tokio-xmpp error
|
||||
TokioXMPP(crate::error::Error),
|
||||
}
|
||||
|
||||
impl ServerConnectorError for Error {}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::Dns(e) => write!(fmt, "{:?}", e),
|
||||
Error::Resolve(e) => write!(fmt, "{:?}", e),
|
||||
Error::Idna => write!(fmt, "IDNA error"),
|
||||
Error::Tls(e) => write!(fmt, "TLS error: {}", e),
|
||||
Self::Dns(e) => write!(fmt, "{:?}", e),
|
||||
Self::Resolve(e) => write!(fmt, "{:?}", e),
|
||||
Self::Idna => write!(fmt, "IDNA error"),
|
||||
Self::Tls(e) => write!(fmt, "TLS error: {}", e),
|
||||
#[cfg(all(feature = "tls-rust", not(feature = "tls-native")))]
|
||||
Error::DnsNameError(e) => write!(fmt, "DNS name error: {}", e),
|
||||
Error::TokioXMPP(e) => write!(fmt, "TokioXMPP error: {}", e),
|
||||
Self::DnsNameError(e) => write!(fmt, "DNS name error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {}
|
||||
|
||||
impl From<crate::error::Error> for Error {
|
||||
fn from(e: crate::error::Error) -> Self {
|
||||
Error::TokioXMPP(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TlsError> for Error {
|
||||
fn from(e: TlsError) -> Self {
|
||||
Error::Tls(e)
|
||||
Self::Tls(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "tls-rust", not(feature = "tls-native")))]
|
||||
impl From<InvalidDnsNameError> for Error {
|
||||
fn from(e: InvalidDnsNameError) -> Self {
|
||||
Error::DnsNameError(e)
|
||||
Self::DnsNameError(e)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use super::error::Error;
|
||||
use super::error::Error as StartTlsError;
|
||||
use crate::Error;
|
||||
use futures::{future::select_ok, FutureExt};
|
||||
use hickory_resolver::{
|
||||
config::LookupIpStrategy, name_server::TokioConnectionProvider, IntoName, TokioAsyncResolver,
|
||||
|
|
@ -8,23 +9,21 @@ use std::net::SocketAddr;
|
|||
use tokio::net::TcpStream;
|
||||
|
||||
pub async fn connect_to_host(domain: &str, port: u16) -> Result<TcpStream, Error> {
|
||||
let ascii_domain = idna::domain_to_ascii(&domain).map_err(|_| Error::Idna)?;
|
||||
let ascii_domain = idna::domain_to_ascii(&domain).map_err(|_| StartTlsError::Idna)?;
|
||||
|
||||
if let Ok(ip) = ascii_domain.parse() {
|
||||
return Ok(TcpStream::connect(&SocketAddr::new(ip, port))
|
||||
.await
|
||||
.map_err(|e| Error::from(crate::Error::Io(e)))?);
|
||||
return Ok(TcpStream::connect(&SocketAddr::new(ip, port)).await?);
|
||||
}
|
||||
|
||||
let (config, mut options) =
|
||||
hickory_resolver::system_conf::read_system_conf().map_err(Error::Resolve)?;
|
||||
hickory_resolver::system_conf::read_system_conf().map_err(StartTlsError::Resolve)?;
|
||||
options.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
|
||||
let resolver = TokioAsyncResolver::new(config, options, TokioConnectionProvider::default());
|
||||
|
||||
let ips = resolver
|
||||
.lookup_ip(ascii_domain)
|
||||
.await
|
||||
.map_err(Error::Resolve)?;
|
||||
.map_err(StartTlsError::Resolve)?;
|
||||
// Happy Eyeballs: connect to all records in parallel, return the
|
||||
// first to succeed
|
||||
select_ok(
|
||||
|
|
@ -33,7 +32,7 @@ pub async fn connect_to_host(domain: &str, port: u16) -> Result<TcpStream, Error
|
|||
)
|
||||
.await
|
||||
.map(|(result, _)| result)
|
||||
.map_err(|_| crate::Error::Disconnected.into())
|
||||
.map_err(|_| crate::Error::Disconnected)
|
||||
}
|
||||
|
||||
pub async fn connect_with_srv(
|
||||
|
|
@ -41,20 +40,18 @@ pub async fn connect_with_srv(
|
|||
srv: &str,
|
||||
fallback_port: u16,
|
||||
) -> Result<TcpStream, Error> {
|
||||
let ascii_domain = idna::domain_to_ascii(&domain).map_err(|_| Error::Idna)?;
|
||||
let ascii_domain = idna::domain_to_ascii(&domain).map_err(|_| StartTlsError::Idna)?;
|
||||
|
||||
if let Ok(ip) = ascii_domain.parse() {
|
||||
debug!("Attempting connection to {ip}:{fallback_port}");
|
||||
return Ok(TcpStream::connect(&SocketAddr::new(ip, fallback_port))
|
||||
.await
|
||||
.map_err(|e| Error::from(crate::Error::Io(e)))?);
|
||||
return Ok(TcpStream::connect(&SocketAddr::new(ip, fallback_port)).await?);
|
||||
}
|
||||
|
||||
let resolver = TokioAsyncResolver::tokio_from_system_conf().map_err(Error::Resolve)?;
|
||||
let resolver = TokioAsyncResolver::tokio_from_system_conf().map_err(StartTlsError::Resolve)?;
|
||||
|
||||
let srv_domain = format!("{}.{}.", srv, ascii_domain)
|
||||
.into_name()
|
||||
.map_err(Error::Dns)?;
|
||||
.map_err(StartTlsError::Dns)?;
|
||||
let srv_records = resolver.srv_lookup(srv_domain.clone()).await.ok();
|
||||
|
||||
match srv_records {
|
||||
|
|
|
|||
|
|
@ -28,10 +28,11 @@ use tokio::{
|
|||
use xmpp_parsers::{jid::Jid, ns};
|
||||
|
||||
use crate::error::ProtocolError;
|
||||
use crate::Error;
|
||||
use crate::{connect::ServerConnector, xmpp_codec::Packet, AsyncClient, SimpleClient};
|
||||
use crate::{connect::ServerConnectorError, xmpp_stream::XMPPStream};
|
||||
|
||||
use self::error::Error;
|
||||
use self::error::Error as StartTlsError;
|
||||
use self::happy_eyeballs::{connect_to_host, connect_with_srv};
|
||||
|
||||
mod client;
|
||||
|
|
@ -58,11 +59,8 @@ pub enum ServerConfig {
|
|||
},
|
||||
}
|
||||
|
||||
impl ServerConnectorError for Error {}
|
||||
|
||||
impl ServerConnector for ServerConfig {
|
||||
type Stream = TlsStream<TcpStream>;
|
||||
type Error = Error;
|
||||
async fn connect(&self, jid: &Jid, ns: &str) -> Result<XMPPStream<Self::Stream>, Error> {
|
||||
// TCP connection
|
||||
let tcp_stream = match self {
|
||||
|
|
@ -100,11 +98,9 @@ impl ServerConnector for ServerConfig {
|
|||
// TODO: Add support for TLS 1.2 and earlier.
|
||||
Some(tokio_rustls::rustls::ProtocolVersion::TLSv1_3) => {
|
||||
let data = vec![0u8; 32];
|
||||
let data = connection.export_keying_material(
|
||||
data,
|
||||
b"EXPORTER-Channel-Binding",
|
||||
None,
|
||||
)?;
|
||||
let data = connection
|
||||
.export_keying_material(data, b"EXPORTER-Channel-Binding", None)
|
||||
.map_err(|e| StartTlsError::Tls(e))?;
|
||||
ChannelBinding::TlsExporter(data)
|
||||
}
|
||||
_ => ChannelBinding::None,
|
||||
|
|
@ -121,7 +117,8 @@ async fn get_tls_stream<S: AsyncRead + AsyncWrite + Unpin>(
|
|||
let stream = xmpp_stream.into_inner();
|
||||
let tls_stream = TlsConnector::from(NativeTlsConnector::builder().build().unwrap())
|
||||
.connect(&domain, stream)
|
||||
.await?;
|
||||
.await
|
||||
.map_err(|e| StartTlsError::Tls(e))?;
|
||||
Ok(tls_stream)
|
||||
}
|
||||
|
||||
|
|
@ -130,7 +127,7 @@ async fn get_tls_stream<S: AsyncRead + AsyncWrite + Unpin>(
|
|||
xmpp_stream: XMPPStream<S>,
|
||||
) -> Result<TlsStream<S>, Error> {
|
||||
let domain = xmpp_stream.jid.domain().to_string();
|
||||
let domain = ServerName::try_from(domain)?;
|
||||
let domain = ServerName::try_from(domain).map_err(|e| StartTlsError::DnsNameError(e))?;
|
||||
let stream = xmpp_stream.into_inner();
|
||||
let root_store = RootCertStore {
|
||||
roots: webpki_roots::TLS_SERVER_ROOTS.into(),
|
||||
|
|
|
|||
|
|
@ -4,13 +4,9 @@ use std::sync::Arc;
|
|||
|
||||
use tokio::net::TcpStream;
|
||||
|
||||
use crate::{
|
||||
connect::{ServerConnector, ServerConnectorError},
|
||||
xmpp_stream::XMPPStream,
|
||||
Component,
|
||||
};
|
||||
use crate::{connect::ServerConnector, xmpp_stream::XMPPStream, Component};
|
||||
|
||||
use self::error::Error;
|
||||
use crate::Error;
|
||||
|
||||
mod component;
|
||||
pub mod error;
|
||||
|
|
@ -31,16 +27,13 @@ impl TcpServerConnector {
|
|||
}
|
||||
}
|
||||
|
||||
impl ServerConnectorError for Error {}
|
||||
|
||||
impl ServerConnector for TcpServerConnector {
|
||||
type Stream = TcpStream;
|
||||
type Error = Error;
|
||||
async fn connect(
|
||||
&self,
|
||||
jid: &xmpp_parsers::jid::Jid,
|
||||
ns: &str,
|
||||
) -> Result<XMPPStream<Self::Stream>, Self::Error> {
|
||||
) -> Result<XMPPStream<Self::Stream>, Error> {
|
||||
let stream = TcpStream::connect(&*self.0)
|
||||
.await
|
||||
.map_err(|e| crate::Error::Io(e))?;
|
||||
|
|
|
|||
Loading…
Reference in a new issue