ferron/config/
mod.rs

1pub mod adapters;
2mod lookup;
3pub mod processing;
4
5pub use ferron_common::config::*;
6
7use std::error::Error;
8use std::sync::Arc;
9
10use fancy_regex::RegexBuilder;
11
12pub use self::lookup::*;
13use crate::util::IpBlockList;
14
15/// Parses conditional data
16pub fn parse_conditional_data(
17  name: &str,
18  value: ServerConfigurationEntry,
19) -> Result<ConditionalData, Box<dyn Error + Send + Sync>> {
20  Ok(match name {
21    "is_remote_ip" => {
22      let mut list = IpBlockList::new();
23      list.load_from_vec(value.values.iter().filter_map(|v| v.as_str()).collect());
24      ConditionalData::IsRemoteIp(list)
25    }
26    "is_forwarded_for" => {
27      let mut list = IpBlockList::new();
28      list.load_from_vec(value.values.iter().filter_map(|v| v.as_str()).collect());
29      ConditionalData::IsForwardedFor(list)
30    }
31    "is_not_remote_ip" => {
32      let mut list = IpBlockList::new();
33      list.load_from_vec(value.values.iter().filter_map(|v| v.as_str()).collect());
34      ConditionalData::IsNotRemoteIp(list)
35    }
36    "is_not_forwarded_for" => {
37      let mut list = IpBlockList::new();
38      list.load_from_vec(value.values.iter().filter_map(|v| v.as_str()).collect());
39      ConditionalData::IsNotForwardedFor(list)
40    }
41    "is_equal" => ConditionalData::IsEqual(
42      value
43        .values
44        .first()
45        .and_then(|v| v.as_str())
46        .ok_or(anyhow::anyhow!(
47          "Missing or invalid left side of a \"is_equal\" subcondition"
48        ))?
49        .to_string(),
50      value
51        .values
52        .get(1)
53        .and_then(|v| v.as_str())
54        .ok_or(anyhow::anyhow!(
55          "Missing or invalid right side of a \"is_equal\" subcondition"
56        ))?
57        .to_string(),
58    ),
59    "is_not_equal" => ConditionalData::IsNotEqual(
60      value
61        .values
62        .first()
63        .and_then(|v| v.as_str())
64        .ok_or(anyhow::anyhow!(
65          "Missing or invalid left side of a \"is_not_equal\" subcondition"
66        ))?
67        .to_string(),
68      value
69        .values
70        .get(1)
71        .and_then(|v| v.as_str())
72        .ok_or(anyhow::anyhow!(
73          "Missing or invalid right side of a \"is_not_equal\" subcondition"
74        ))?
75        .to_string(),
76    ),
77    "is_regex" => {
78      let left_side = value.values.first().and_then(|v| v.as_str()).ok_or(anyhow::anyhow!(
79        "Missing or invalid left side of a \"is_regex\" subcondition"
80      ))?;
81      let right_side = value.values.get(1).and_then(|v| v.as_str()).ok_or(anyhow::anyhow!(
82        "Missing or invalid right side of a \"is_regex\" subcondition"
83      ))?;
84      ConditionalData::IsRegex(
85        left_side.to_string(),
86        RegexBuilder::new(right_side)
87          .case_insensitive(
88            value
89              .props
90              .get("case_insensitive")
91              .and_then(|p| p.as_bool())
92              .unwrap_or(false),
93          )
94          .build()?,
95      )
96    }
97    "is_not_regex" => {
98      let left_side = value.values.first().and_then(|v| v.as_str()).ok_or(anyhow::anyhow!(
99        "Missing or invalid left side of a \"is_not_regex\" subcondition"
100      ))?;
101      let right_side = value.values.get(1).and_then(|v| v.as_str()).ok_or(anyhow::anyhow!(
102        "Missing or invalid right side of a \"is_not_regex\" subcondition"
103      ))?;
104      ConditionalData::IsNotRegex(
105        left_side.to_string(),
106        RegexBuilder::new(right_side)
107          .case_insensitive(
108            value
109              .props
110              .get("case_insensitive")
111              .and_then(|p| p.as_bool())
112              .unwrap_or(false),
113          )
114          .build()?,
115      )
116    }
117    "is_rego" => {
118      let rego_policy = value
119        .values
120        .first()
121        .and_then(|v| v.as_str())
122        .ok_or(anyhow::anyhow!("Missing or invalid Rego policy"))?;
123      let mut rego_engine = regorus::Engine::new();
124      rego_engine.add_policy("ferron.rego".to_string(), rego_policy.to_string())?;
125      ConditionalData::IsRego(Arc::new(rego_engine))
126    }
127    "set_constant" => ConditionalData::SetConstant(
128      value
129        .values
130        .first()
131        .and_then(|v| v.as_str())
132        .ok_or(anyhow::anyhow!(
133          "Missing or invalid constant name in a \"set_constant\" subcondition"
134        ))?
135        .to_string(),
136      value
137        .values
138        .get(1)
139        .and_then(|v| v.as_str())
140        .ok_or(anyhow::anyhow!(
141          "Missing or invalid constant value in a \"set_constant\" subcondition"
142        ))?
143        .to_string(),
144    ),
145    "is_language" => ConditionalData::IsLanguage(
146      value
147        .values
148        .first()
149        .and_then(|v| v.as_str())
150        .ok_or(anyhow::anyhow!(
151          "Missing or invalid desired language in a \"is_language\" subcondition"
152        ))?
153        .to_string(),
154    ),
155    _ => Err(anyhow::anyhow!("Unrecognized subcondition: {name}"))?,
156  })
157}