Skip to main content

actrpc_interceptor/interceptors/policy/
matcher.rs

1use crate::interceptors::policy::{
2    config::{PolicyMatcher, PolicyMatcherKind},
3    error::PolicyError,
4};
5use globset::{Glob, GlobMatcher};
6use regex::Regex;
7
8#[derive(Debug, Clone)]
9pub struct CompiledPolicyMatcher {
10    negated: bool,
11    inner: CompiledPolicyMatcherInner,
12}
13
14#[derive(Debug, Clone)]
15enum CompiledPolicyMatcherInner {
16    Exact(String),
17    Glob(GlobMatcher),
18    Regex(Regex),
19}
20
21impl CompiledPolicyMatcher {
22    pub fn compile(rule: &str, matcher: &PolicyMatcher) -> Result<Self, PolicyError> {
23        let inner = match matcher.kind {
24            PolicyMatcherKind::Exact => CompiledPolicyMatcherInner::Exact(matcher.value.clone()),
25
26            PolicyMatcherKind::Glob => {
27                let glob =
28                    Glob::new(&matcher.value).map_err(|source| PolicyError::InvalidGlob {
29                        rule: rule.to_owned(),
30                        source,
31                    })?;
32
33                CompiledPolicyMatcherInner::Glob(glob.compile_matcher())
34            }
35
36            PolicyMatcherKind::Regex => {
37                let regex =
38                    Regex::new(&matcher.value).map_err(|source| PolicyError::InvalidRegex {
39                        rule: rule.to_owned(),
40                        source,
41                    })?;
42
43                CompiledPolicyMatcherInner::Regex(regex)
44            }
45        };
46
47        Ok(Self {
48            negated: matcher.negated,
49            inner,
50        })
51    }
52
53    pub fn matches(&self, value: Option<&str>) -> bool {
54        let matched = match value {
55            Some(value) => match &self.inner {
56                CompiledPolicyMatcherInner::Exact(expected) => value == expected,
57                CompiledPolicyMatcherInner::Glob(glob) => glob.is_match(value),
58                CompiledPolicyMatcherInner::Regex(regex) => regex.is_match(value),
59            },
60            None => false,
61        };
62
63        if self.negated { !matched } else { matched }
64    }
65}