toasty-driver-postgresql 0.5.0

PostgreSQL driver for Toasty
Documentation
mod config;
mod connect;

use config::{SslVerifyMode, build_client_config};
pub(crate) use connect::MakeRustlsConnect;

use tokio_postgres::Config;
use url::Url;

pub(crate) fn configure_tls(
    url: &Url,
    config: &mut Config,
) -> Result<Option<MakeRustlsConnect>, toasty_core::Error> {
    let mut sslmode = SslVerifyMode::Prefer;
    let mut sslrootcert: Option<String> = None;
    let mut sslcert: Option<String> = None;
    let mut sslkey: Option<String> = None;

    for (key, value) in url.query_pairs() {
        match key.as_ref() {
            "sslmode" => {
                sslmode = match value.as_ref() {
                    "disable" => SslVerifyMode::Disable,
                    "prefer" => SslVerifyMode::Prefer,
                    "require" => SslVerifyMode::Require,
                    "verify-ca" => SslVerifyMode::VerifyCa,
                    "verify-full" => SslVerifyMode::VerifyFull,
                    other => {
                        return Err(toasty_core::Error::invalid_connection_url(format!(
                            "unsupported sslmode: {other}"
                        )));
                    }
                };
            }
            "sslrootcert" => {
                sslrootcert = Some(value.into_owned());
            }
            "sslcert" => {
                sslcert = Some(value.into_owned());
            }
            "sslkey" => {
                sslkey = Some(value.into_owned());
            }
            "channel_binding" => {
                let cb = match value.as_ref() {
                    "disable" => tokio_postgres::config::ChannelBinding::Disable,
                    "prefer" => tokio_postgres::config::ChannelBinding::Prefer,
                    "require" => tokio_postgres::config::ChannelBinding::Require,
                    other => {
                        return Err(toasty_core::Error::invalid_connection_url(format!(
                            "unsupported channel_binding: {other}"
                        )));
                    }
                };
                config.channel_binding(cb);
            }
            "sslnegotiation" => {
                let neg = match value.as_ref() {
                    "postgres" => tokio_postgres::config::SslNegotiation::Postgres,
                    "direct" => tokio_postgres::config::SslNegotiation::Direct,
                    other => {
                        return Err(toasty_core::Error::invalid_connection_url(format!(
                            "unsupported sslnegotiation: {other}"
                        )));
                    }
                };
                config.ssl_negotiation(neg);
            }
            _ => {}
        }
    }

    let ssl_mode = match sslmode {
        SslVerifyMode::Disable => tokio_postgres::config::SslMode::Disable,
        SslVerifyMode::Prefer => tokio_postgres::config::SslMode::Prefer,
        SslVerifyMode::Require | SslVerifyMode::VerifyCa | SslVerifyMode::VerifyFull => {
            tokio_postgres::config::SslMode::Require
        }
    };
    config.ssl_mode(ssl_mode);

    if sslmode != SslVerifyMode::Disable {
        let rustls_config = build_client_config(
            sslmode,
            sslrootcert.as_deref(),
            sslcert.as_deref(),
            sslkey.as_deref(),
        )?;
        Ok(Some(MakeRustlsConnect::new(rustls_config)))
    } else {
        Ok(None)
    }
}