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
15pub 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}