actrpc-interceptor 0.1.0

Concrete interceptors for ActRPC.
Documentation
use crate::interceptors::policy::{
    config::{PolicyMatcher, PolicyMatcherKind},
    error::PolicyError,
};
use globset::{Glob, GlobMatcher};
use regex::Regex;

#[derive(Debug, Clone)]
pub struct CompiledPolicyMatcher {
    negated: bool,
    inner: CompiledPolicyMatcherInner,
}

#[derive(Debug, Clone)]
enum CompiledPolicyMatcherInner {
    Exact(String),
    Glob(GlobMatcher),
    Regex(Regex),
}

impl CompiledPolicyMatcher {
    pub fn compile(rule: &str, matcher: &PolicyMatcher) -> Result<Self, PolicyError> {
        let inner = match matcher.kind {
            PolicyMatcherKind::Exact => CompiledPolicyMatcherInner::Exact(matcher.value.clone()),

            PolicyMatcherKind::Glob => {
                let glob =
                    Glob::new(&matcher.value).map_err(|source| PolicyError::InvalidGlob {
                        rule: rule.to_owned(),
                        source,
                    })?;

                CompiledPolicyMatcherInner::Glob(glob.compile_matcher())
            }

            PolicyMatcherKind::Regex => {
                let regex =
                    Regex::new(&matcher.value).map_err(|source| PolicyError::InvalidRegex {
                        rule: rule.to_owned(),
                        source,
                    })?;

                CompiledPolicyMatcherInner::Regex(regex)
            }
        };

        Ok(Self {
            negated: matcher.negated,
            inner,
        })
    }

    pub fn matches(&self, value: Option<&str>) -> bool {
        let matched = match value {
            Some(value) => match &self.inner {
                CompiledPolicyMatcherInner::Exact(expected) => value == expected,
                CompiledPolicyMatcherInner::Glob(glob) => glob.is_match(value),
                CompiledPolicyMatcherInner::Regex(regex) => regex.is_match(value),
            },
            None => false,
        };

        if self.negated { !matched } else { matched }
    }
}