fips_configuration 0.1.0

FIPS Configuration, used to configure the FIPS server
Documentation
use crate::modes::fips::FIPS;
use crate::modes::host_static::STATIC;
use crate::modes::mock::MOCK;
use crate::modes::proxy::PROXY;

use hyper::Uri;
use fips_plugin_registry::plugin::ExternalFunctions;
use serde::{Deserialize, Serialize};
use std::{
    collections::HashMap,
    fmt::{Display, Formatter},
    ops::{Deref, DerefMut},
};
use schemars::JsonSchema;

use thiserror::Error;

#[derive(Error, Debug)]
pub enum RuleCollectionError {
    #[error("Could not parse URI: {0}")]
    UriParseError(#[from] hyper::http::uri::InvalidUri),
    #[error("Could not format String: {0}")]
    StringFromatError(#[from] std::fmt::Error),
}

const MACH_ALL_REQUESTS_STR: &str = "^/.*$";

#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)]
pub enum RuleCollection {
    Static(STATIC),
    Mock(MOCK),
    Proxy(PROXY),
    Fips(FIPS),
}

impl Default for RuleCollection {
    fn default() -> RuleCollection {
        RuleCollection::Static(STATIC {
            name: Some(String::from(
                "static asset fallback rule if no others found",
            )),
            match_body_contains: None,
            match_methods: None,
            match_with_prob: None,
            sleep: None,
            selected: true,
            active: true,
            path: String::from(MACH_ALL_REQUESTS_STR),
            headers: None,
            static_base_dir: String::from(std::env::current_dir().unwrap().to_str().unwrap()),
        })
    }
}

pub trait ProxyFunctions {
    fn get_forward_uri(&self) -> String;
    fn get_forward_headers(&self) -> Option<Vec<String>>;
    fn get_backward_headers(&self) -> Option<Vec<String>>;
    fn form_forward_path(&self, uri: &Uri) -> Result<Uri, RuleCollectionError>;
}

pub trait RuleTransformingFunctions {
    fn apply_plugins(&mut self, template: &ExternalFunctions);
}

pub trait CommonFunctions {
    fn get_name(&self) -> Option<String>;
    fn get_path(&self) -> String;
    fn get_match_with_prob(&self) -> Option<f32>;
    fn get_match_body_contains(&self) -> Option<String>;
    fn get_match_methods(&self) -> Option<Vec<String>>;
    fn get_selected(&self) -> bool;
    fn get_sleep(&self) -> Option<u64>;
    fn get_active(&self) -> bool;
    fn get_headers(&self) -> Option<HashMap<String, String>>;
    fn set_selected(&mut self);
    fn set_unselected(&mut self);
    fn set_active(&mut self);
    fn set_inactive(&mut self);
}

impl Deref for RuleCollection {
    type Target = dyn CommonFunctions;

    fn deref(&self) -> &Self::Target {
        match self {
            RuleCollection::Static(s) => s,
            RuleCollection::Mock(s) => s,
            RuleCollection::Proxy(s) => s,
            RuleCollection::Fips(s) => s,
        }
    }
}

impl DerefMut for RuleCollection {
    fn deref_mut(&mut self) -> &mut Self::Target {
        match self {
            RuleCollection::Static(s) => s,
            RuleCollection::Mock(s) => s,
            RuleCollection::Proxy(s) => s,
            RuleCollection::Fips(s) => s,
        }
    }
}

impl Display for RuleCollection {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
        match self {
            RuleCollection::Static(_s) => write!(f, "STATIC"),
            RuleCollection::Mock(_s) => write!(f, "MOCK"),
            RuleCollection::Proxy(_s) => write!(f, "PROXY"),
            RuleCollection::Fips(_s) => write!(f, "FIPS"),
        }
    }
}

pub fn default_as_true() -> bool {
    true
}

pub fn apply_plugins(value: &mut serde_json::Value, plugins: &ExternalFunctions) {
    match value {
        serde_json::Value::String(val) => {
            if plugins.has(val) {
                let result = plugins.call(val, vec![]).expect("Invocation failed");
                let try_serialize = serde_json::from_str(&result);
                if let Ok(i) = try_serialize {
                    *value = i;
                } else {
                    *value = serde_json::Value::String(result);
                }
            }
        }
        serde_json::Value::Array(val) => {
            for i in val {
                apply_plugins(i, plugins);
            }
        }
        serde_json::Value::Object(val) => {
            let plugin = val.get("plugin");
            let args = val.get("args");
            match (plugin, args) {
                (Some(p), Some(a)) => {
                    if let (
                        serde_json::Value::String(function),
                        serde_json::Value::Array(arguments),
                    ) = (p, a)
                    {
                        let result = plugins
                            .call(function, arguments.clone())
                            .expect("Invocation failed");
                        let try_serialize = serde_json::from_str(&result);
                        if let Ok(i) = try_serialize {
                            *value = i;
                        } else {
                            *value = serde_json::Value::String(result);
                        }
                    }
                }
                _ => {
                    for (_, i) in val {
                        apply_plugins(i, plugins);
                    }
                }
            }
        }
        _ => {}
    }
}