libvault 0.2.2

the libvault is modified from RustyVault
Documentation
use serde_json::{Value, json};

use super::{PkiBackend, PkiBackendInner, field, util};
use crate::{
    errors::RvError,
    logical::{Backend, Operation, Path, Request, Response},
    utils,
};

impl PkiBackend {
    pub fn root_generate_path(&self) -> Path {
        let backend = self.inner.clone();

        let mut path = Path::builder()
            .pattern(r"root/tls/generate/(?P<exported>.+)")
            .operation(Operation::Write, {
                let handler = backend.clone();
                move |backend, req| {
                    let handler = handler.clone();
                    Box::pin(async move { handler.generate_root(backend, req).await })
                }
            })
            .help("Generate a new CA certificate and private key used for signing.")
            .build();

        path.fields.extend(field::ca_common_fields());
        path.fields.extend(field::ca_key_generation_fields());
        path.fields.extend(field::ca_issue_fields());

        path
    }

    pub fn root_delete_path(&self) -> Path {
        let backend = self.inner.clone();

        Path::builder()
            .pattern(r"root/tls")
            .operation(Operation::Delete, {
                let handler = backend.clone();
                move |backend, req| {
                    let handler = handler.clone();
                    Box::pin(async move { handler.delete_root(backend, req).await })
                }
            })
            .help("Deletes the root CA key to allow a new one to be generated.")
            .build()
    }
}

impl PkiBackendInner {
    pub async fn generate_root(
        &self,
        _backend: &dyn Backend,
        req: &mut Request,
    ) -> Result<Option<Response>, RvError> {
        let mut export_private_key = false;
        if req
            .get_data_or_default("exported")?
            .as_str()
            .ok_or(RvError::ErrRequestFieldInvalid)?
            == "exported"
        {
            export_private_key = true;
        }

        let role_entry = util::get_role_params(req)?;

        let mut cert = util::generate_certificate(&role_entry, req)?;

        cert.is_ca = true;

        let cert_bundle = cert.to_cert_bundle(None, None)?;

        self.store_ca_bundle(req, &cert_bundle).await?;

        let cert_expiration =
            utils::asn1time_to_timestamp(cert_bundle.certificate.not_after().to_string().as_str())?;

        let mut resp_data = json!({
            "expiration": cert_expiration,
            "issuing_ca": String::from_utf8_lossy(&cert_bundle.certificate.to_pem()?),
            "certificate": String::from_utf8_lossy(&cert_bundle.certificate.to_pem()?),
            "serial_number": cert_bundle.serial_number.clone(),
        })
        .as_object()
        .unwrap()
        .clone();

        if export_private_key {
            resp_data.insert(
                "private_key".to_string(),
                Value::String(
                    String::from_utf8_lossy(&cert_bundle.private_key.private_key_to_pem_pkcs8()?)
                        .to_string(),
                ),
            );
            resp_data.insert(
                "private_key_type".to_string(),
                Value::String(cert_bundle.private_key_type.clone()),
            );
        }

        Ok(Some(Response::data_response(Some(resp_data))))
    }

    pub async fn delete_root(
        &self,
        _backend: &dyn Backend,
        req: &mut Request,
    ) -> Result<Option<Response>, RvError> {
        self.delete_ca_bundle(req).await?;
        Ok(None)
    }
}