terrazzo-terminal 0.2.8

A simple web-based terminal emulator built on Terrazzo.
use std::convert::Infallible;
use std::sync::Arc;

use nameth::NamedEnumValues as _;
use nameth::nameth;
use openssl::asn1::Asn1Time;
use openssl::x509::X509;
use openssl::x509::store::X509Store;
use trz_gateway_common::certificate_info::CertificateInfo;
use trz_gateway_common::certificate_info::X509CertificateInfo;
use trz_gateway_common::security_configuration::certificate::CertificateConfig;
use trz_gateway_common::security_configuration::certificate::as_trusted_store::AsTrustedStoreError;
use trz_gateway_common::security_configuration::certificate::as_trusted_store::as_trusted_store;
use trz_gateway_common::security_configuration::certificate::cache::CachedCertificate;
use trz_gateway_common::security_configuration::certificate::pem::PemCertificate;
use trz_gateway_common::security_configuration::trusted_store::TrustedStoreConfig;
use trz_gateway_common::x509::name::CertitficateName;
use trz_gateway_common::x509::validity::Validity;
use trz_gateway_server::server::root_ca_configuration;
use trz_gateway_server::server::root_ca_configuration::RootCaConfigError;

use super::config::DynConfig;

#[derive(Clone)]
pub struct PrivateRootCa(CachedCertificate);

impl PrivateRootCa {
    pub fn load(config: &DynConfig) -> Result<Self, PrivateRootCaError> {
        let server = &config.server;
        let root_ca = server
            .with(|server| {
                root_ca_configuration::load_root_ca(
                    CertitficateName {
                        organization: Some("Terrazzo"),
                        common_name: Some("Terrazzo Terminal Root CA"),
                        ..CertitficateName::default()
                    },
                    CertificateInfo {
                        certificate: server.private_root_ca.with_added_extension("cert"),
                        private_key: server.private_root_ca.with_added_extension("key"),
                    },
                    Validity {
                        from: 0,
                        to: 365 * 20,
                    }
                    .try_map(Asn1Time::days_from_now)
                    .expect("Asn1Time::days_from_now")
                    .as_deref()
                    .try_into()
                    .expect("Asn1Time to SystemTime"),
                )
            })
            .map_err(PrivateRootCaError::Load)?
            .cache()
            .map_err(PrivateRootCaError::Cache)?;
        Ok(Self(root_ca))
    }
}

#[nameth]
#[derive(thiserror::Error, Debug)]
pub enum PrivateRootCaError {
    #[error("[{n}] {0}", n = self.name())]
    Load(RootCaConfigError),

    #[error("[{n}] {0}", n = self.name())]
    Cache(<PemCertificate as CertificateConfig>::Error),
}

impl CertificateConfig for PrivateRootCa {
    type Error = Infallible;

    fn intermediates(&self) -> Result<Arc<Vec<X509>>, Self::Error> {
        self.0.intermediates()
    }

    fn certificate(&self) -> Result<Arc<X509CertificateInfo>, Self::Error> {
        self.0.certificate()
    }
}

impl TrustedStoreConfig for PrivateRootCa {
    type Error = AsTrustedStoreError<Infallible>;

    fn root_certificates(&self) -> Result<Arc<X509Store>, Self::Error> {
        as_trusted_store(self)
    }
}

mod debug {
    use std::fmt::Debug;

    use super::PrivateRootCa;

    impl Debug for PrivateRootCa {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            f.debug_tuple("PrivateRootCa").finish()
        }
    }
}