use std::{
    fmt,
    fs::File,
    io::Read,
    path::{Path, PathBuf},
};
use lookup::lookup_v2::OptionalValuePath;
use openssl::{
    pkcs12::{ParsedPkcs12_2, Pkcs12},
    pkey::{PKey, Private},
    ssl::{select_next_proto, AlpnError, ConnectConfiguration, SslContextBuilder, SslVerifyMode},
    stack::Stack,
    x509::{store::X509StoreBuilder, X509},
};
use snafu::ResultExt;
use vector_config::configurable_component;
use super::{
    AddCertToStoreSnafu, AddExtraChainCertSnafu, CaStackPushSnafu, DerExportSnafu,
    EncodeAlpnProtocolsSnafu, FileOpenFailedSnafu, FileReadFailedSnafu, MaybeTls, NewCaStackSnafu,
    NewStoreBuilderSnafu, ParsePkcs12Snafu, Pkcs12Snafu, PrivateKeyParseSnafu, Result,
    SetAlpnProtocolsSnafu, SetCertificateSnafu, SetPrivateKeySnafu, SetVerifyCertSnafu, TlsError,
    TlsIdentitySnafu, X509ParseSnafu,
};
pub const PEM_START_MARKER: &str = "-----BEGIN ";
pub const TEST_PEM_CA_PATH: &str = "tests/data/ca/certs/ca.cert.pem";
pub const TEST_PEM_INTERMEDIATE_CA_PATH: &str =
    "tests/data/ca/intermediate_server/certs/ca-chain.cert.pem";
pub const TEST_PEM_CRT_PATH: &str =
    "tests/data/ca/intermediate_server/certs/localhost-chain.cert.pem";
pub const TEST_PEM_KEY_PATH: &str = "tests/data/ca/intermediate_server/private/localhost.key.pem";
pub const TEST_PEM_CLIENT_CRT_PATH: &str =
    "tests/data/ca/intermediate_client/certs/localhost-chain.cert.pem";
pub const TEST_PEM_CLIENT_KEY_PATH: &str =
    "tests/data/ca/intermediate_client/private/localhost.key.pem";
#[configurable_component]
#[configurable(metadata(docs::advanced))]
#[derive(Clone, Debug, Default)]
pub struct TlsEnableableConfig {
    pub enabled: Option<bool>,
    #[serde(flatten)]
    pub options: TlsConfig,
}
impl TlsEnableableConfig {
    pub fn enabled() -> Self {
        Self {
            enabled: Some(true),
            ..Self::default()
        }
    }
    pub fn test_config() -> Self {
        Self {
            enabled: Some(true),
            options: TlsConfig::test_config(),
        }
    }
}
#[configurable_component]
#[derive(Clone, Debug, Default)]
pub struct TlsSourceConfig {
    pub client_metadata_key: Option<OptionalValuePath>,
    #[serde(flatten)]
    pub tls_config: TlsEnableableConfig,
}
#[configurable_component]
#[configurable(metadata(docs::advanced))]
#[derive(Clone, Debug, Default)]
#[serde(deny_unknown_fields)]
pub struct TlsConfig {
    pub verify_certificate: Option<bool>,
    pub verify_hostname: Option<bool>,
    #[configurable(metadata(docs::examples = "h2"))]
    pub alpn_protocols: Option<Vec<String>>,
    #[serde(alias = "ca_path")]
    #[configurable(metadata(docs::examples = "/path/to/certificate_authority.crt"))]
    #[configurable(metadata(docs::human_name = "CA File Path"))]
    pub ca_file: Option<PathBuf>,
    #[serde(alias = "crt_path")]
    #[configurable(metadata(docs::examples = "/path/to/host_certificate.crt"))]
    #[configurable(metadata(docs::human_name = "Certificate File Path"))]
    pub crt_file: Option<PathBuf>,
    #[serde(alias = "key_path")]
    #[configurable(metadata(docs::examples = "/path/to/host_certificate.key"))]
    #[configurable(metadata(docs::human_name = "Key File Path"))]
    pub key_file: Option<PathBuf>,
    #[configurable(metadata(docs::examples = "${KEY_PASS_ENV_VAR}"))]
    #[configurable(metadata(docs::examples = "PassWord1"))]
    #[configurable(metadata(docs::human_name = "Key File Password"))]
    pub key_pass: Option<String>,
    #[serde(alias = "server_name")]
    #[configurable(metadata(docs::examples = "www.example.com"))]
    #[configurable(metadata(docs::human_name = "Server Name"))]
    pub server_name: Option<String>,
}
impl TlsConfig {
    pub fn test_config() -> Self {
        Self {
            ca_file: Some(TEST_PEM_CA_PATH.into()),
            crt_file: Some(TEST_PEM_CRT_PATH.into()),
            key_file: Some(TEST_PEM_KEY_PATH.into()),
            ..Self::default()
        }
    }
}
#[derive(Clone, Default)]
pub struct TlsSettings {
    verify_certificate: bool,
    pub(super) verify_hostname: bool,
    authorities: Vec<X509>,
    pub(super) identity: Option<IdentityStore>, alpn_protocols: Option<Vec<u8>>,
    server_name: Option<String>,
}
#[derive(Clone)]
pub(super) struct IdentityStore(Vec<u8>, String);
impl TlsSettings {
    pub fn from_options(options: &Option<TlsConfig>) -> Result<Self> {
        Self::from_options_base(options, false)
    }
    pub(super) fn from_options_base(options: &Option<TlsConfig>, for_server: bool) -> Result<Self> {
        let default = TlsConfig::default();
        let options = options.as_ref().unwrap_or(&default);
        if !for_server {
            if options.verify_certificate == Some(false) {
                warn!(
                    "The `verify_certificate` option is DISABLED, this may lead to security vulnerabilities."
                );
            }
            if options.verify_hostname == Some(false) {
                warn!("The `verify_hostname` option is DISABLED, this may lead to security vulnerabilities.");
            }
        }
        Ok(Self {
            verify_certificate: options.verify_certificate.unwrap_or(!for_server),
            verify_hostname: options.verify_hostname.unwrap_or(!for_server),
            authorities: options.load_authorities()?,
            identity: options.load_identity()?,
            alpn_protocols: options.parse_alpn_protocols()?,
            server_name: options.server_name.clone(),
        })
    }
    fn identity(&self) -> Option<ParsedPkcs12_2> {
        self.identity.as_ref().map(|identity| {
            Pkcs12::from_der(&identity.0)
                .expect("Could not build PKCS#12 archive from parsed data")
                .parse2(&identity.1)
                .expect("Could not parse stored PKCS#12 archive")
        })
    }
    pub fn identity_pem(&self) -> Option<(Vec<u8>, Vec<u8>)> {
        self.identity().map(|identity| {
            let mut cert = identity
                .cert
                .expect("Identity required")
                .to_pem()
                .expect("Invalid stored identity");
            if let Some(chain) = identity.ca {
                for authority in chain {
                    cert.extend(
                        authority
                            .to_pem()
                            .expect("Invalid stored identity chain certificate"),
                    );
                }
            }
            let key = identity
                .pkey
                .expect("Private key required")
                .private_key_to_pem_pkcs8()
                .expect("Invalid stored private key");
            (cert, key)
        })
    }
    pub fn authorities_pem(&self) -> impl Iterator<Item = Vec<u8>> + '_ {
        self.authorities.iter().map(|authority| {
            authority
                .to_pem()
                .expect("Invalid stored authority certificate")
        })
    }
    pub(super) fn apply_context(&self, context: &mut SslContextBuilder) -> Result<()> {
        self.apply_context_base(context, false)
    }
    pub(super) fn apply_context_base(
        &self,
        context: &mut SslContextBuilder,
        for_server: bool,
    ) -> Result<()> {
        context.set_verify(if self.verify_certificate {
            SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT
        } else {
            SslVerifyMode::NONE
        });
        if let Some(identity) = self.identity() {
            if let Some(cert) = &identity.cert {
                context.set_certificate(cert).context(SetCertificateSnafu)?;
            }
            if let Some(pkey) = &identity.pkey {
                context.set_private_key(pkey).context(SetPrivateKeySnafu)?;
            }
            if let Some(chain) = identity.ca {
                for cert in chain {
                    context
                        .add_extra_chain_cert(cert)
                        .context(AddExtraChainCertSnafu)?;
                }
            }
        }
        if self.authorities.is_empty() {
            debug!("Fetching system root certs.");
            #[cfg(windows)]
            load_windows_certs(context).unwrap();
            #[cfg(target_os = "macos")]
            load_mac_certs(context).unwrap();
        } else {
            let mut store = X509StoreBuilder::new().context(NewStoreBuilderSnafu)?;
            for authority in &self.authorities {
                store
                    .add_cert(authority.clone())
                    .context(AddCertToStoreSnafu)?;
            }
            context
                .set_verify_cert_store(store.build())
                .context(SetVerifyCertSnafu)?;
        }
        if let Some(alpn) = &self.alpn_protocols {
            if for_server {
                let server_proto = alpn.clone();
                context.set_alpn_select_callback(move |_, client_proto| {
                    select_next_proto(server_proto.as_slice(), client_proto).ok_or(AlpnError::NOACK)
                });
            } else {
                context
                    .set_alpn_protos(alpn.as_slice())
                    .context(SetAlpnProtocolsSnafu)?;
            }
        }
        Ok(())
    }
    pub fn apply_connect_configuration(
        &self,
        connection: &mut ConnectConfiguration,
    ) -> std::result::Result<(), openssl::error::ErrorStack> {
        connection.set_verify_hostname(self.verify_hostname);
        if let Some(server_name) = &self.server_name {
            connection.set_use_server_name_indication(false);
            connection.set_hostname(server_name)?;
        }
        Ok(())
    }
}
impl TlsConfig {
    fn load_authorities(&self) -> Result<Vec<X509>> {
        match &self.ca_file {
            None => Ok(vec![]),
            Some(filename) => {
                let (data, filename) = open_read(filename, "certificate")?;
                der_or_pem(
                    data,
                    |der| X509::from_der(&der).map(|x509| vec![x509]),
                    |pem| {
                        pem.match_indices(PEM_START_MARKER)
                            .map(|(start, _)| X509::from_pem(pem[start..].as_bytes()))
                            .collect()
                    },
                )
                .with_context(|_| X509ParseSnafu { filename })
            }
        }
    }
    fn load_identity(&self) -> Result<Option<IdentityStore>> {
        match (&self.crt_file, &self.key_file) {
            (None, Some(_)) => Err(TlsError::MissingCrtKeyFile),
            (None, None) => Ok(None),
            (Some(filename), _) => {
                let (data, filename) = open_read(filename, "certificate")?;
                der_or_pem(
                    data,
                    |der| self.parse_pkcs12_identity(der),
                    |pem| self.parse_pem_identity(&pem, &filename),
                )
            }
        }
    }
    fn parse_alpn_protocols(&self) -> Result<Option<Vec<u8>>> {
        match &self.alpn_protocols {
            None => Ok(None),
            Some(protocols) => {
                let mut data: Vec<u8> = Vec::new();
                for str in protocols {
                    data.push(str.len().try_into().context(EncodeAlpnProtocolsSnafu)?);
                    data.append(&mut str.clone().into_bytes());
                }
                Ok(Some(data))
            }
        }
    }
    fn parse_pem_identity(&self, pem: &str, crt_file: &Path) -> Result<Option<IdentityStore>> {
        match &self.key_file {
            None => Err(TlsError::MissingKey),
            Some(key_file) => {
                let name = crt_file.to_string_lossy().to_string();
                let mut crt_stack = X509::stack_from_pem(pem.as_bytes())
                    .with_context(|_| X509ParseSnafu { filename: crt_file })?
                    .into_iter();
                let crt = crt_stack.next().ok_or(TlsError::MissingCertificate)?;
                let key = load_key(key_file, &self.key_pass)?;
                let mut ca_stack = Stack::new().context(NewCaStackSnafu)?;
                for intermediate in crt_stack {
                    ca_stack.push(intermediate).context(CaStackPushSnafu)?;
                }
                let pkcs12 = Pkcs12::builder()
                    .ca(ca_stack)
                    .name(&name)
                    .pkey(&key)
                    .cert(&crt)
                    .build2("")
                    .context(Pkcs12Snafu)?;
                let identity = pkcs12.to_der().context(DerExportSnafu)?;
                pkcs12.parse2("").context(TlsIdentitySnafu)?;
                Ok(Some(IdentityStore(identity, String::new())))
            }
        }
    }
    fn parse_pkcs12_identity(&self, der: Vec<u8>) -> Result<Option<IdentityStore>> {
        let pkcs12 = Pkcs12::from_der(&der).context(ParsePkcs12Snafu)?;
        let key_pass = self.key_pass.as_deref().unwrap_or("");
        pkcs12.parse2(key_pass).context(ParsePkcs12Snafu)?;
        Ok(Some(IdentityStore(der, key_pass.to_string())))
    }
}
#[cfg(windows)]
fn load_windows_certs(builder: &mut SslContextBuilder) -> Result<()> {
    use super::SchannelSnafu;
    let mut store = X509StoreBuilder::new().context(NewStoreBuilderSnafu)?;
    let current_user_store =
        schannel::cert_store::CertStore::open_current_user("ROOT").context(SchannelSnafu)?;
    for cert in current_user_store.certs() {
        let cert = cert.to_der().to_vec();
        let cert = X509::from_der(&cert[..]).context(super::X509SystemParseSnafu)?;
        store.add_cert(cert).context(AddCertToStoreSnafu)?;
    }
    builder
        .set_verify_cert_store(store.build())
        .context(SetVerifyCertSnafu)?;
    Ok(())
}
#[cfg(target_os = "macos")]
fn load_mac_certs(builder: &mut SslContextBuilder) -> Result<()> {
    use std::collections::HashMap;
    use security_framework::trust_settings::{Domain, TrustSettings, TrustSettingsForCertificate};
    use super::SecurityFrameworkSnafu;
    let mut store = X509StoreBuilder::new().context(NewStoreBuilderSnafu)?;
    let mut all_certs = HashMap::new();
    for domain in &[Domain::User, Domain::Admin, Domain::System] {
        let ts = TrustSettings::new(*domain);
        for cert in ts.iter().context(SecurityFrameworkSnafu)? {
            let trusted = ts
                .tls_trust_settings_for_certificate(&cert)
                .context(SecurityFrameworkSnafu)?
                .unwrap_or(TrustSettingsForCertificate::TrustRoot);
            all_certs.entry(cert.to_der()).or_insert(trusted);
        }
    }
    for (cert, trusted) in all_certs {
        if matches!(
            trusted,
            TrustSettingsForCertificate::TrustRoot | TrustSettingsForCertificate::TrustAsRoot
        ) {
            let cert = X509::from_der(&cert[..]).context(super::X509SystemParseSnafu)?;
            store.add_cert(cert).context(AddCertToStoreSnafu)?;
        }
    }
    builder
        .set_verify_cert_store(store.build())
        .context(SetVerifyCertSnafu)?;
    Ok(())
}
impl fmt::Debug for TlsSettings {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TlsSettings")
            .field("verify_certificate", &self.verify_certificate)
            .field("verify_hostname", &self.verify_hostname)
            .finish_non_exhaustive()
    }
}
pub type MaybeTlsSettings = MaybeTls<(), TlsSettings>;
impl MaybeTlsSettings {
    pub fn enable_client() -> Result<Self> {
        let tls = TlsSettings::from_options_base(&None, false)?;
        Ok(Self::Tls(tls))
    }
    pub fn tls_client(config: &Option<TlsConfig>) -> Result<Self> {
        Ok(Self::Tls(TlsSettings::from_options_base(config, false)?))
    }
    pub fn from_config(config: &Option<TlsEnableableConfig>, for_server: bool) -> Result<Self> {
        match config {
            None => Ok(Self::Raw(())), Some(config) => {
                if config.enabled.unwrap_or(false) {
                    let tls =
                        TlsSettings::from_options_base(&Some(config.options.clone()), for_server)?;
                    match (for_server, &tls.identity) {
                        (true, None) => Err(TlsError::MissingRequiredIdentity),
                        _ => Ok(Self::Tls(tls)),
                    }
                } else {
                    Ok(Self::Raw(())) }
            }
        }
    }
    pub const fn http_protocol_name(&self) -> &'static str {
        match self {
            MaybeTls::Raw(()) => "http",
            MaybeTls::Tls(_) => "https",
        }
    }
}
impl From<TlsSettings> for MaybeTlsSettings {
    fn from(tls: TlsSettings) -> Self {
        Self::Tls(tls)
    }
}
fn load_key(filename: &Path, pass_phrase: &Option<String>) -> Result<PKey<Private>> {
    let (data, filename) = open_read(filename, "key")?;
    match pass_phrase {
        None => der_or_pem(
            data,
            |der| PKey::private_key_from_der(&der),
            |pem| PKey::private_key_from_pem(pem.as_bytes()),
        )
        .with_context(|_| PrivateKeyParseSnafu { filename }),
        Some(phrase) => der_or_pem(
            data,
            |der| PKey::private_key_from_pkcs8_passphrase(&der, phrase.as_bytes()),
            |pem| PKey::private_key_from_pem_passphrase(pem.as_bytes(), phrase.as_bytes()),
        )
        .with_context(|_| PrivateKeyParseSnafu { filename }),
    }
}
fn der_or_pem<T>(data: Vec<u8>, der_fn: impl Fn(Vec<u8>) -> T, pem_fn: impl Fn(String) -> T) -> T {
    match String::from_utf8(data) {
        Ok(text) => match text.find(PEM_START_MARKER) {
            Some(_) => pem_fn(text),
            None => der_fn(text.into_bytes()),
        },
        Err(err) => der_fn(err.into_bytes()),
    }
}
fn open_read(filename: &Path, note: &'static str) -> Result<(Vec<u8>, PathBuf)> {
    if let Some(filename) = filename.to_str() {
        if filename.contains(PEM_START_MARKER) {
            return Ok((Vec::from(filename), "inline text".into()));
        }
    }
    let mut text = Vec::<u8>::new();
    File::open(filename)
        .with_context(|_| FileOpenFailedSnafu { note, filename })?
        .read_to_end(&mut text)
        .with_context(|_| FileReadFailedSnafu { note, filename })?;
    Ok((text, filename.into()))
}
#[cfg(test)]
mod test {
    use super::*;
    const TEST_PKCS12_PATH: &str = "tests/data/ca/intermediate_client/private/localhost.p12";
    const TEST_PEM_CRT_BYTES: &[u8] =
        include_bytes!("../../../../tests/data/ca/intermediate_server/certs/localhost.cert.pem");
    const TEST_PEM_KEY_BYTES: &[u8] =
        include_bytes!("../../../../tests/data/ca/intermediate_server/private/localhost.key.pem");
    #[test]
    fn parse_alpn_protocols() {
        let options = TlsConfig {
            alpn_protocols: Some(vec![String::from("h2")]),
            ..Default::default()
        };
        let settings =
            TlsSettings::from_options(&Some(options)).expect("Failed to parse alpn_protocols");
        assert_eq!(settings.alpn_protocols, Some(vec![2, 104, 50]));
    }
    #[test]
    fn from_options_pkcs12() {
        let _provider = openssl::provider::Provider::try_load(None, "legacy", true).unwrap();
        let options = TlsConfig {
            crt_file: Some(TEST_PKCS12_PATH.into()),
            key_pass: Some("NOPASS".into()),
            ..Default::default()
        };
        let settings =
            TlsSettings::from_options(&Some(options)).expect("Failed to load PKCS#12 certificate");
        assert!(settings.identity.is_some());
        assert_eq!(settings.authorities.len(), 0);
    }
    #[test]
    fn from_options_pem() {
        let options = TlsConfig {
            crt_file: Some(TEST_PEM_CRT_PATH.into()),
            key_file: Some(TEST_PEM_KEY_PATH.into()),
            ..Default::default()
        };
        let settings =
            TlsSettings::from_options(&Some(options)).expect("Failed to load PEM certificate");
        assert!(settings.identity.is_some());
        assert_eq!(settings.authorities.len(), 0);
    }
    #[test]
    fn from_options_inline_pem() {
        let crt = String::from_utf8(TEST_PEM_CRT_BYTES.to_vec()).unwrap();
        let key = String::from_utf8(TEST_PEM_KEY_BYTES.to_vec()).unwrap();
        let options = TlsConfig {
            crt_file: Some(crt.into()),
            key_file: Some(key.into()),
            ..Default::default()
        };
        let settings =
            TlsSettings::from_options(&Some(options)).expect("Failed to load PEM certificate");
        assert!(settings.identity.is_some());
        assert_eq!(settings.authorities.len(), 0);
    }
    #[test]
    fn from_options_ca() {
        let options = TlsConfig {
            ca_file: Some(TEST_PEM_CA_PATH.into()),
            ..Default::default()
        };
        let settings = TlsSettings::from_options(&Some(options))
            .expect("Failed to load authority certificate");
        assert!(settings.identity.is_none());
        assert_eq!(settings.authorities.len(), 1);
    }
    #[test]
    fn from_options_inline_ca() {
        let ca = String::from_utf8(
            include_bytes!("../../../../tests/data/ca/certs/ca.cert.pem").to_vec(),
        )
        .unwrap();
        let options = TlsConfig {
            ca_file: Some(ca.into()),
            ..Default::default()
        };
        let settings = TlsSettings::from_options(&Some(options))
            .expect("Failed to load authority certificate");
        assert!(settings.identity.is_none());
        assert_eq!(settings.authorities.len(), 1);
    }
    #[test]
    fn from_options_intermediate_ca() {
        let options = TlsConfig {
            ca_file: Some("tests/data/ca/intermediate_server/certs/ca-chain.cert.pem".into()),
            ..Default::default()
        };
        let settings = TlsSettings::from_options(&Some(options))
            .expect("Failed to load authority certificate");
        assert!(settings.identity.is_none());
        assert_eq!(settings.authorities.len(), 2);
    }
    #[test]
    fn from_options_multi_ca() {
        let options = TlsConfig {
            ca_file: Some("tests/data/Multi_CA.crt".into()),
            ..Default::default()
        };
        let settings = TlsSettings::from_options(&Some(options))
            .expect("Failed to load authority certificate");
        assert!(settings.identity.is_none());
        assert_eq!(settings.authorities.len(), 2);
    }
    #[test]
    fn from_options_none() {
        let settings = TlsSettings::from_options(&None).expect("Failed to generate null settings");
        assert!(settings.identity.is_none());
        assert_eq!(settings.authorities.len(), 0);
    }
    #[test]
    fn from_options_bad_certificate() {
        let options = TlsConfig {
            key_file: Some(TEST_PEM_KEY_PATH.into()),
            ..Default::default()
        };
        let error = TlsSettings::from_options(&Some(options))
            .expect_err("from_options failed to check certificate");
        assert!(matches!(error, TlsError::MissingCrtKeyFile));
        let options = TlsConfig {
            crt_file: Some(TEST_PEM_CRT_PATH.into()),
            ..Default::default()
        };
        let _error = TlsSettings::from_options(&Some(options))
            .expect_err("from_options failed to check certificate");
        }
    #[test]
    fn from_config_none() {
        assert!(MaybeTlsSettings::from_config(&None, true).unwrap().is_raw());
        assert!(MaybeTlsSettings::from_config(&None, false)
            .unwrap()
            .is_raw());
    }
    #[test]
    fn from_config_not_enabled() {
        assert!(settings_from_config(None, false, false, true).is_raw());
        assert!(settings_from_config(None, false, false, false).is_raw());
        assert!(settings_from_config(Some(false), false, false, true).is_raw());
        assert!(settings_from_config(Some(false), false, false, false).is_raw());
    }
    #[test]
    fn from_config_fails_without_certificate() {
        let config = make_config(Some(true), false, false);
        let error = MaybeTlsSettings::from_config(&Some(config), true)
            .expect_err("from_config failed to check for a certificate");
        assert!(matches!(error, TlsError::MissingRequiredIdentity));
    }
    #[test]
    fn from_config_with_certificate() {
        let config = settings_from_config(Some(true), true, true, true);
        assert!(config.is_tls());
    }
    fn settings_from_config(
        enabled: Option<bool>,
        set_crt: bool,
        set_key: bool,
        for_server: bool,
    ) -> MaybeTlsSettings {
        let config = make_config(enabled, set_crt, set_key);
        MaybeTlsSettings::from_config(&Some(config), for_server)
            .expect("Failed to generate settings from config")
    }
    fn make_config(enabled: Option<bool>, set_crt: bool, set_key: bool) -> TlsEnableableConfig {
        TlsEnableableConfig {
            enabled,
            options: TlsConfig {
                crt_file: set_crt.then(|| TEST_PEM_CRT_PATH.into()),
                key_file: set_key.then(|| TEST_PEM_KEY_PATH.into()),
                ..Default::default()
            },
        }
    }
}