Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
WafCondition.cs
1using System;
3using System.IO;
4using System.Text.RegularExpressions;
5using System.Threading.Tasks;
6using System.Xml;
7using Waher.Content;
12using Waher.Script;
14
16{
20 public abstract class WafCondition : WafComparison
21 {
22 private readonly EnumAttribute<ComparisonMode> mode;
23 private readonly StringAttribute value;
24
28 public WafCondition()
29 : base()
30 {
31 }
32
39 public WafCondition(XmlElement Xml, WafAction Parent, WebApplicationFirewall Document)
40 : base(Xml, Parent, Document)
41 {
42 this.value = new StringAttribute(Xml, "value");
43 this.mode = new EnumAttribute<ComparisonMode>(Xml, "mode");
44 }
45
52 public async Task<WafResult?> Review(ProcessingState State, string Property)
53 {
54 if (await this.Applies(State, Property))
55 return await this.ReviewChildren(State);
56 else
57 return null;
58 }
59
66 public async Task<bool> Applies(ProcessingState State, string Property)
67 {
69 ComparisonMode Mode = await this.mode.EvaluateAsync(Variables, ComparisonMode.ContainsRegex);
70 string Value = await this.value.EvaluateAsync(Variables, string.Empty);
71
72 switch (Mode)
73 {
74 case ComparisonMode.ContainsRegex:
75 Regex Regex = GetRegex(Value, false);
76 Match M = Regex.Match(Property);
77 return M.Success;
78
79 case ComparisonMode.StartsWithRegex:
80 Regex = GetRegex(Value, false);
81 M = Regex.Match(Property);
82 return M.Success && M.Index == 0;
83
84 case ComparisonMode.EndsWithRegex:
85 Regex = GetRegex(Value, false);
86 M = Regex.Match(Property);
87 return M.Success && M.Index + M.Length == Property.Length;
88
89 case ComparisonMode.ExactRegex:
90 Regex = GetRegex(Value, false);
91 M = Regex.Match(Property);
92 return M.Success && M.Index == 0 && M.Length == Property.Length;
93
94 case ComparisonMode.ContainsConstant:
95 return Property.Contains(Value, StringComparison.CurrentCulture);
96
97 case ComparisonMode.StartsWithConstant:
98 return Property.StartsWith(Value, StringComparison.CurrentCulture);
99
100 case ComparisonMode.EndsWithConstant:
101 return Property.EndsWith(Value, StringComparison.CurrentCulture);
102
103 case ComparisonMode.ExactConstant:
104 return Property.Equals(Value, StringComparison.CurrentCulture);
105
106 case ComparisonMode.ContainsRegexIgnoreCase:
107 Regex = GetRegex(Value, true);
108 M = Regex.Match(Property);
109 return M.Success;
110
111 case ComparisonMode.StartsWithRegexIgnoreCase:
112 Regex = GetRegex(Value, true);
113 M = Regex.Match(Property);
114 return M.Success && M.Index == 0;
115
116 case ComparisonMode.EndsWithRegexIgnoreCase:
117 Regex = GetRegex(Value, true);
118 M = Regex.Match(Property);
119 return M.Success && M.Index + M.Length == Property.Length;
120
121 case ComparisonMode.ExactRegexIgnoreCase:
122 Regex = GetRegex(Value, true);
123 M = Regex.Match(Property);
124 return M.Success && M.Index == 0 && M.Length == Property.Length;
125
126 case ComparisonMode.ContainsConstantIgnoreCase:
127 return Property.Contains(Value, StringComparison.CurrentCultureIgnoreCase);
128
129 case ComparisonMode.StartsWithConstantIgnoreCase:
130 return Property.StartsWith(Value, StringComparison.CurrentCultureIgnoreCase);
131
132 case ComparisonMode.EndsWithConstantIgnoreCase:
133 return Property.EndsWith(Value, StringComparison.CurrentCultureIgnoreCase);
134
135 case ComparisonMode.ExactConstantIgnoreCase:
136 return Property.Equals(Value, StringComparison.CurrentCultureIgnoreCase);
137
138 case ComparisonMode.Script:
139 Expression Expression = GetExpression(Value);
140 object Result = await Expression.EvaluateAsync(Variables);
141 return Result is bool b && b;
142
143 case ComparisonMode.List:
144 Dictionary<string, bool> List = GetList(Value, false);
145 return List.ContainsKey(Property);
146
147 case ComparisonMode.ListIgnoreCase:
148 List = GetList(Value, true);
149 return List.ContainsKey(Property);
150
151 case ComparisonMode.FileList:
152 List = await this.GetFileList(Value, false);
153 return List.ContainsKey(Property);
154
155 case ComparisonMode.FileListIgnoreCase:
156 List = await this.GetFileList(Value, true);
157 return List.ContainsKey(Property);
158
159 case ComparisonMode.DatabaseList:
160 string Key = "DB|" + Value + "|" + Property;
161 if (State.TryGetCachedObject(Key, out bool Included))
162 return Included;
163
164 WafListProperty DbEntry = await Database.FindFirstIgnoreRest<WafListProperty>(
165 new FilterAnd(
166 new FilterFieldEqualTo("List", Value),
167 new FilterFieldEqualTo("Property", Property)));
168
169 Included = !(DbEntry is null);
170 State.AddToCache(Key, Included, fiveMinutes);
171 return Included;
172
173 case ComparisonMode.DatabaseListIgnoreCase:
174 Key = "DBCI|" + Value + "|" + Property;
175 if (State.TryGetCachedObject(Key, out Included))
176 return Included;
177
178 WafListPropertyIgnoreCase DbEntry2 = await Database.FindFirstIgnoreRest<WafListPropertyIgnoreCase>(
179 new FilterAnd(
180 new FilterFieldEqualTo("List", new CaseInsensitiveString(Value)),
181 new FilterFieldEqualTo("Property", new CaseInsensitiveString(Property))));
182
183 Included = !(DbEntry2 is null);
184 State.AddToCache(Key, Included, fiveMinutes);
185 return Included;
186
187 default:
188 return false;
189 }
190 }
191
192 private static Regex GetRegex(string Pattern, bool IgnoreCase)
193 {
194 Dictionary<string, Regex> Expressions = IgnoreCase ?
195 regularExpressionsIgnoreCase : regularExpressions;
196
197 lock (Expressions)
198 {
199 if (!Expressions.TryGetValue(Pattern, out Regex Result))
200 {
201 RegexOptions Options = RegexOptions.Compiled | RegexOptions.Singleline;
202 if (IgnoreCase)
203 Options |= RegexOptions.IgnoreCase;
204
205 Result = new Regex(Pattern, Options);
206 Expressions[Pattern] = Result;
207 }
208
209 return Result;
210 }
211 }
212
213 private static Expression GetExpression(string s)
214 {
215 lock (expressions)
216 {
217 if (!expressions.TryGetValue(s, out Expression Result))
218 {
219 Result = new Expression(s);
220 expressions[s] = Result;
221 }
222
223 return Result;
224 }
225 }
226
227 private static Dictionary<string, bool> GetList(string Pattern, bool IgnoreCase)
228 {
229 Dictionary<string, Dictionary<string, bool>> Lists = IgnoreCase ?
230 listsIgnoreCase : lists;
231
232 lock (Lists)
233 {
234 if (!Lists.TryGetValue(Pattern, out Dictionary<string, bool> Result))
235 {
236 Result = new Dictionary<string, bool>(IgnoreCase ?
237 StringComparer.CurrentCultureIgnoreCase : StringComparer.CurrentCulture);
238
239 foreach (string Part in Pattern.Split(',', StringSplitOptions.RemoveEmptyEntries))
240 Result[Part.Trim()] = true;
241
242 Lists[Pattern] = Result;
243 }
244
245 return Result;
246 }
247 }
248
249 private async Task<Dictionary<string, bool>> GetFileList(string FileName, bool IgnoreCase)
250 {
251 Dictionary<string, FileListInfo> Lists = IgnoreCase ?
252 fileListsIgnoreCase : fileLists;
253
254 FileListInfo Result;
255 DateTime Check = DateTime.UtcNow;
256 DateTime LastWriteTime = DateTime.MinValue;
257
258 lock (Lists)
259 {
260 if (Lists.TryGetValue(FileName, out Result))
261 {
262 if (Check.Subtract(Result.LastTimeCheckUtc).TotalMinutes <= 1)
263 return Result.Values;
264
265 LastWriteTime = File.GetLastWriteTimeUtc(Result.FullPath);
266 if (LastWriteTime == Result.LastWriteTimeUtc)
267 {
268 Result.LastTimeCheckUtc = Check;
269 return Result.Values;
270 }
271 }
272 }
273
274 string FullFileName = Path.Combine(this.Document.AppDataFolder, FileName);
275 string FileContent = await File.ReadAllTextAsync(FullFileName);
276
277 if (LastWriteTime == DateTime.MinValue)
278 LastWriteTime = File.GetLastWriteTimeUtc(FullFileName);
279
280 Dictionary<string, bool> List = new Dictionary<string, bool>(IgnoreCase ?
281 StringComparer.CurrentCultureIgnoreCase : StringComparer.CurrentCulture);
282
283 Result = new FileListInfo()
284 {
285 FullPath = FullFileName,
286 LastWriteTimeUtc = LastWriteTime,
287 LastTimeCheckUtc = Check,
288 Values = List
289 };
290
291 foreach (string Row in FileContent.Split(CommonTypes.CRLF, StringSplitOptions.RemoveEmptyEntries))
292 List[Row.Trim()] = true;
293
294 lock (Lists)
295 {
296 Lists[FileName] = Result;
297 }
298
299 return Result.Values;
300 }
301
302 private static readonly Dictionary<string, Regex> regularExpressions = new Dictionary<string, Regex>();
303 private static readonly Dictionary<string, Regex> regularExpressionsIgnoreCase = new Dictionary<string, Regex>();
304 private static readonly Dictionary<string, Expression> expressions = new Dictionary<string, Expression>();
305 private static readonly Dictionary<string, Dictionary<string, bool>> lists = new Dictionary<string, Dictionary<string, bool>>();
306 private static readonly Dictionary<string, Dictionary<string, bool>> listsIgnoreCase = new Dictionary<string, Dictionary<string, bool>>();
307 private static readonly Dictionary<string, FileListInfo> fileLists = new Dictionary<string, FileListInfo>();
308 private static readonly Dictionary<string, FileListInfo> fileListsIgnoreCase = new Dictionary<string, FileListInfo>();
309
310 private class FileListInfo
311 {
312 public string FullPath;
313 public Dictionary<string, bool> Values;
314 public DateTime LastWriteTimeUtc;
315 public DateTime LastTimeCheckUtc;
316 }
317 }
318}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:15
static readonly char[] CRLF
Contains the CR LF character sequence.
Definition: CommonTypes.cs:19
Represents a case-insensitive string.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:21
This filter selects objects that conform to all child-filters provided.
Definition: FilterAnd.cs:10
This filter selects objects that have a named field equal to a given value.
Class managing a script expression.
Definition: Expression.cs:41
async Task< object > EvaluateAsync(Variables Variables)
Evaluates the expression, using the variables provided in the Variables collection....
Definition: Expression.cs:4461
Collection of variables.
Definition: Variables.cs:25
Abstract base class for Web Application Firewall comparisons.
Definition: WafComparison.cs:9
Abstract base class for Web Application Firewall conditions.
Definition: WafCondition.cs:21
async Task< bool > Applies(ProcessingState State, string Property)
Checks if the condition applies.
Definition: WafCondition.cs:66
async Task< WafResult?> Review(ProcessingState State, string Property)
Reviews the processing state, and returns a WAF result, if any.
Definition: WafCondition.cs:52
WafCondition(XmlElement Xml, WafAction Parent, WebApplicationFirewall Document)
Abstract base class for Web Application Firewall conditions.
Definition: WafCondition.cs:39
WafCondition()
Abstract base class for Web Application Firewall conditions.
Definition: WafCondition.cs:28
Contains information about a property in a database list.
Contains information about a property in a database list.
Contains the current state of a review process.
Variables Variables
Set of variables.
void AddToCache(string Key, object Value)
Adds a value to the cache.
Abstract base class for Web Application Firewall actions.
Definition: WafAction.cs:17
WebApplicationFirewall Document
Web Application Firewall document.
Definition: WafAction.cs:60
static readonly TimeSpan fiveMinutes
Five minutes time span.
Definition: WafAction.cs:131
async Task< WafResult?> ReviewChildren(ProcessingState State)
Reviews the processing state, and returns a WAF result, if any.
Definition: WafActions.cs:72
Web Application Firewall for HttpServer.
string AppDataFolder
Application data folder, where content files are stored.
ComparisonMode
Condition comparison mode.