#![allow(clippy::module_name_repetitions)]
use crate::error::{Error, Result};
use hyper::client::HttpConnector;
use hyper_rustls::HttpsConnector;
use hyper_rustls::HttpsConnectorBuilder;
use rustls::pki_types::CertificateDer;
use rustls::RootCertStore;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd)]
pub struct TlsConfig {
custom_cert: Option<String>,
}
impl TlsConfig {
#[must_use]
pub fn new(custom_cert: Option<String>) -> Self {
Self { custom_cert }
}
#[must_use]
pub fn get_connector_from_tls(&self) -> HttpsConnector<HttpConnector> {
let tls = self.get_client_config();
let mut http = HttpConnector::new();
http.enforce_http(false);
HttpsConnectorBuilder::new()
.with_tls_config(tls)
.https_or_http()
.enable_http2()
.wrap_connector(http)
}
pub fn get_client_config(&self) -> rustls::ClientConfig {
if let Some(cert) = &self.custom_cert {
return get_client_config_with_custom_certs(cert).unwrap();
}
get_client_config_native_certs()
}
}
fn get_client_config_native_certs() -> rustls::ClientConfig {
let root_store = RootCertStore {
roots: webpki_roots::TLS_SERVER_ROOTS.into(),
};
rustls::ClientConfig::builder()
.with_root_certificates(root_store)
.with_no_client_auth()
}
fn get_client_config_with_custom_certs(ca_cert: &str) -> Result<rustls::ClientConfig> {
let roots = root_store_from_cert_file(ca_cert)?;
let config = rustls::ClientConfig::builder()
.with_root_certificates(roots)
.with_no_client_auth();
Ok(config)
}
fn root_store_from_cert_file(filename: &str) -> Result<RootCertStore> {
let certfile = std::fs::File::open(filename).map_err(Error::LoadTLSCertificateError)?;
let mut reader = std::io::BufReader::new(certfile);
let certs: Vec<CertificateDer> = rustls_pemfile::certs(&mut reader)
.filter_map(|result| result.ok())
.collect();
let mut roots = rustls::RootCertStore::empty();
roots.add_parsable_certificates(certs);
Ok(roots)
}