libvault 0.2.2

the libvault is modified from RustyVault
Documentation
use serde::{Deserialize, Serialize};

use super::{CertBackend, CertBackendInner};
use crate::{
    errors::RvError,
    logical::{Backend, Field, FieldType, Operation, Path, Request, Response},
    storage::StorageEntry,
};

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Config {
    pub disable_binding: bool,
    pub enable_identity_alias_metadata: bool,
    pub ocsp_cache_size: i64,
}

impl CertBackend {
    pub fn config_path(&self) -> Path {
        let backend_read = self.inner.clone();
        let backend_write = self.inner.clone();

        Path::builder()
            .pattern(r"config")
            .field(
                "disable_binding",
                Field::builder()
                    .field_type(FieldType::Bool)
                    .default_value(false)
                    .description(
                        r#"If set, during renewal, skips the matching of presented client identity with the client identity used during login. Defaults to false."#,
                    ),
            )
            .field(
                "enable_identity_alias_metadata",
                Field::builder()
                    .field_type(FieldType::Bool)
                    .default_value(false)
                    .description(
                        r#"If set, metadata of the certificate including the metadata corresponding to allowed_metadata_extensions will be stored in the alias. Defaults to false."#,
                    ),
            )
            .field(
                "ocsp_cache_size",
                Field::builder()
                    .field_type(FieldType::Int)
                    .default_value(100)
                    .description(
                        "The size of the in memory OCSP response cache, shared by all configured certs",
                    ),
            )
            .operation(Operation::Read, {
                let handler = backend_read.clone();
                move |backend, req| {
                    let handler = handler.clone();
                    Box::pin(async move { handler.read_config(backend, req).await })
                }
            })
            .operation(Operation::Write, {
                let handler = backend_write.clone();
                move |backend, req| {
                    let handler = handler.clone();
                    Box::pin(async move { handler.write_config(backend, req).await })
                }
            })
            .help(
                r#"
This endpoint allows you to create, read, update, and delete trusted certificates
that are allowed to authenticate.

Deleting a certificate will not revoke auth for prior authenticated connections.
To do this, do a revoke on "login". If you don'log need to revoke login immediately,
then the next renew will cause the lease to expire.
                "#,
            )
            .build()
    }
}

impl CertBackendInner {
    pub async fn get_config(&self, req: &Request) -> Result<Option<Config>, RvError> {
        let storage_entry = req.storage_get("config").await?;
        if storage_entry.is_none() {
            return Ok(Some(Config::default()));
        }

        let entry = storage_entry.unwrap();
        let config: Config = serde_json::from_slice(entry.value.as_slice())?;
        Ok(Some(config))
    }

    pub async fn set_config(&self, req: &mut Request, config: &Config) -> Result<(), RvError> {
        let entry = StorageEntry::new("config", config)?;

        req.storage_put(&entry).await
    }

    pub async fn read_config(
        &self,
        _backend: &dyn Backend,
        req: &mut Request,
    ) -> Result<Option<Response>, RvError> {
        let config = self.get_config(req).await?;
        if config.is_none() {
            return Ok(None);
        }

        let cfg_data = serde_json::to_value(config.unwrap())?;

        Ok(Some(Response::data_response(Some(
            cfg_data.as_object().unwrap().clone(),
        ))))
    }

    pub async fn write_config(
        &self,
        _backend: &dyn Backend,
        req: &mut Request,
    ) -> Result<Option<Response>, RvError> {
        let config = self.get_config(req).await?;
        if config.is_none() {
            return Ok(None);
        }

        let mut cfg = config.unwrap();

        if let Ok(disable_binding_raw) = req.get_data("disable_binding") {
            cfg.disable_binding = disable_binding_raw.as_bool().unwrap();
        }

        if let Ok(enable_identity_alias_metadata_raw) =
            req.get_data("enable_identity_alias_metadata")
        {
            cfg.enable_identity_alias_metadata =
                enable_identity_alias_metadata_raw.as_bool().unwrap();
        }

        if let Ok(ocsp_cache_size_raw) = req.get_data("ocsp_cache_size") {
            let ocsp_cache_size = ocsp_cache_size_raw.as_i64().unwrap();
            if ocsp_cache_size < 2 {
                log::error!("invalid cache size, must be >= 2 and <= max_cache_size");
                return Err(RvError::ErrRequestInvalid);
            }
            cfg.ocsp_cache_size = ocsp_cache_size;
        }

        self.set_config(req, &cfg).await?;

        Ok(None)
    }
}