rustls_tokio_postgres/
lib.rs

1#![forbid(unsafe_code)]
2#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))]
3
4//! A [`tokio_postgres`] TLS connector backed by [`rustls`].
5//!
6//! # Example
7//!
8//! ```rust,no_run
9//! use rustls_tokio_postgres::{config_no_verify, MakeRustlsConnect};
10//! use tokio_postgres::{connect, Config};
11//!
12//! #[tokio::main]
13//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
14//!     static CONFIG: &str = "host=localhost user=postgres";
15//!
16//!     // This rustls config does not verify the server certificate.
17//!     // You can construct your own rustls ClientConfig, or enable the
18//!     // `native-roots` or `webpki-roots` features for other config helpers.
19//!     let config = config_no_verify();
20//!
21//!     // Create the client with the TLS configuration.
22//!     let tls = MakeRustlsConnect::new(config);
23//!     let (_client, _conn) = connect(CONFIG, tls).await?;
24//!
25//!     Ok(())
26//! }
27//! ```
28//!
29//! # Features
30//!
31//! - **channel-binding**: enables TLS channel binding, if supported.
32//! - **native-roots**: enables a helper function for creating a [`rustls::ClientConfig`] using the native roots of your OS.
33//! - **webpki-roots**: enables a helper function for creating a [`rustls::ClientConfig`] using the webpki roots.
34
35use std::{io, sync::Arc};
36
37use rustls::ClientConfig;
38use rustls_pki_types::{InvalidDnsNameError, ServerName};
39use tokio::io::{AsyncRead, AsyncWrite};
40use tokio_postgres::tls::MakeTlsConnect;
41
42mod config;
43mod connect;
44
45#[cfg(feature = "native-roots")]
46pub use config::config_native_roots;
47pub use config::config_no_verify;
48#[cfg(feature = "webpki-roots")]
49pub use config::config_webpki_roots;
50pub use rustls;
51pub use tokio_postgres;
52
53/// A MakeTlsConnect implementation that uses rustls.
54#[derive(Clone)]
55pub struct MakeRustlsConnect {
56    config: Arc<ClientConfig>,
57}
58
59impl MakeRustlsConnect {
60    /// Construct a new `MakeRustlsConnect` instance with the provided [`ClientConfig`].
61    pub fn new(config: ClientConfig) -> Self {
62        Self {
63            config: Arc::new(config),
64        }
65    }
66}
67
68impl<S> MakeTlsConnect<S> for MakeRustlsConnect
69where
70    S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
71{
72    type Stream = connect::TlsStream<S>;
73    type TlsConnect = connect::RustlsConnect;
74    type Error = io::Error;
75
76    fn make_tls_connect(&mut self, hostname: &str) -> Result<Self::TlsConnect, Self::Error> {
77        let server_name = ServerName::try_from(hostname)
78            .map_err(|e: InvalidDnsNameError| {
79                io::Error::new(io::ErrorKind::InvalidInput, e.to_string())
80            })?
81            .to_owned();
82
83        Ok(connect::RustlsConnect {
84            config: self.config.clone(),
85            server_name,
86        })
87    }
88}