use std::time::Duration;
use ipnet::IpNet;
use quinn::Connection;
use quincy::{
auth::{
stream::{AuthMessage, AuthStreamBuilder, AuthStreamMode},
ClientAuthenticator,
},
error::AuthError,
Result,
};
use tokio::time::timeout;
pub struct AuthClient {
authenticator: Box<dyn ClientAuthenticator>,
auth_timeout: Duration,
}
impl AuthClient {
pub fn new(authenticator: Box<dyn ClientAuthenticator>, auth_timeout: Duration) -> Self {
Self {
authenticator,
auth_timeout,
}
}
pub async fn authenticate(&self, connection: &Connection) -> Result<(IpNet, IpNet)> {
let auth_stream_builder = AuthStreamBuilder::new(AuthStreamMode::Client);
let mut auth_stream = auth_stream_builder
.connect(connection, self.auth_timeout)
.await?;
let authentication_payload = self.authenticator.generate_payload().await?;
auth_stream
.send_message(AuthMessage::Authenticate {
payload: authentication_payload,
})
.await?;
let auth_response = timeout(self.auth_timeout, auth_stream.recv_message())
.await
.map_err(|_| AuthError::Timeout)??;
match auth_response {
AuthMessage::Authenticated {
client_address,
server_address,
} => Ok((client_address, server_address)),
AuthMessage::Failed => Err(AuthError::InvalidCredentials)?,
_ => Err(AuthError::InvalidPayload)?,
}
}
}