SEBPatch/SebWindowsConfig/Utilities/SEBURLFilter.cs

345 lines
9.8 KiB
C#

using System;
using System.Text;
using System.Text.RegularExpressions;
using DictObj = System.Collections.Generic.Dictionary<string, object>;
using ListObj = System.Collections.Generic.List<object>;
namespace SebWindowsConfig.Utilities
{
public class SEBURLFilter
{
public bool enableURLFilter;
public bool enableContentFilter;
public ListObj permittedList = new ListObj();
public ListObj prohibitedList = new ListObj();
// Updates filter rule arrays with current settings
public void UpdateFilterRules()
{
if (prohibitedList.Count != 0)
{
prohibitedList.Clear();
}
if (permittedList.Count != 0)
{
permittedList.Clear();
}
enableURLFilter = (bool)SEBSettings.settingsCurrent[SEBSettings.KeyURLFilterEnable];
enableContentFilter = (bool)SEBSettings.settingsCurrent[SEBSettings.KeyURLFilterEnableContentFilter];
// Add global URLFilterRules
ListObj URLFilterRules = (ListObj)SEBSettings.settingsCurrent[SEBSettings.KeyURLFilterRules];
ReadURLFilterRules(URLFilterRules);
// Add URLFilterRules from additional resources
ListObj additionalResources = (ListObj)SEBSettings.settingsCurrent[SEBSettings.KeyAdditionalResources];
ReadFilterRulesFromAdditionalResources(additionalResources);
// If URL filtering is enabled, then
// check if Start URL gets allowed by current filter rules and if not add a rule for the Start URL
string startURLString = (string)SEBSettings.settingsCurrent[SEBSettings.KeyStartURL];
if (enableURLFilter && Uri.TryCreate(startURLString, UriKind.Absolute, out Uri startURL))
{
if (TestURLAllowed(startURL) != URLFilterRuleActions.allow)
{
SEBURLFilterRegexExpression expression;
// If Start URL is not allowed: Create one using the full Start URL
try
{
expression = new SEBURLFilterRegexExpression(startURLString);
}
catch (Exception ex)
{
Logger.AddError("Could not create SEBURLFilterRegexExpression: ", this, ex, ex.Message);
prohibitedList.Clear();
permittedList.Clear();
// Convert these rules and add them to the XULRunner seb keys
CreateSebRuleLists();
return;
}
// Add this Start URL filter expression to the permitted filter list
permittedList.Add(expression);
}
}
// Convert these rules and add them to the XULRunner seb keys
CreateSebRuleLists();
}
public void ReadURLFilterRules(ListObj URLFilterRules)
{
foreach (DictObj URLFilterRule in URLFilterRules)
{
if (URLFilterRule.ContainsKey(SEBSettings.KeyURLFilterRuleRegex) && (bool)URLFilterRule[SEBSettings.KeyURLFilterRuleActive] == true)
{
string expressionString = (string)URLFilterRule[SEBSettings.KeyURLFilterRuleExpression];
if (!String.IsNullOrEmpty(expressionString))
{
Object expression;
bool regex = (bool)URLFilterRule[SEBSettings.KeyURLFilterRuleRegex];
try
{
if (regex)
{
expression = new Regex(expressionString, RegexOptions.IgnoreCase);
}
else
{
expression = new SEBURLFilterRegexExpression(expressionString);
}
}
catch (Exception ex)
{
Logger.AddError("Could not create SEBURLFilterRegexExpression: ", this, ex, ex.Message);
prohibitedList.Clear();
permittedList.Clear();
throw;
}
int action = (int)URLFilterRule[SEBSettings.KeyURLFilterRuleAction];
switch (action)
{
case (int)URLFilterRuleActions.block:
prohibitedList.Add(expression);
break;
case (int)URLFilterRuleActions.allow:
permittedList.Add(expression);
break;
}
}
}
}
}
// Read URLFilterRules from additionalResources
public void ReadFilterRulesFromAdditionalResources(ListObj additionalResources)
{
foreach (DictObj additionalResource in additionalResources)
{
if ((bool)additionalResource[SEBSettings.KeyAdditionalResourcesActive])
{
object URLFilterRules;
if (additionalResource.TryGetValue(SEBSettings.KeyURLFilterRules, out URLFilterRules))
{
ReadURLFilterRules((ListObj)URLFilterRules);
}
// Are there further additional resources in this additional resource?
if (additionalResource.TryGetValue(SEBSettings.KeyAdditionalResources, out object additionalSubResources))
{
if (((ListObj)additionalSubResources).Count != 0)
{
ReadFilterRulesFromAdditionalResources((ListObj)additionalSubResources);
}
}
}
}
}
// Convert these rules and add them to the XULRunner seb keys
public void CreateSebRuleLists()
{
// Set prohibited rules
SEBSettings.settingsCurrent[SEBSettings.KeyUrlFilterBlacklist] = SebRuleStringForSEBURLFilterRuleList(prohibitedList);
// Set permitted rules
SEBSettings.settingsCurrent[SEBSettings.KeyUrlFilterWhitelist] = SebRuleStringForSEBURLFilterRuleList(permittedList);
// All rules are regex
SEBSettings.settingsCurrent[SEBSettings.KeyUrlFilterRulesAsRegex] = true;
// Set if content filter is enabled
SEBSettings.settingsCurrent[SEBSettings.KeyUrlFilterTrustedContent] = !(bool)SEBSettings.settingsCurrent[SEBSettings.KeyURLFilterEnableContentFilter];
}
public string SebRuleStringForSEBURLFilterRuleList(ListObj filterRuleList)
{
if (filterRuleList.Count == 0)
{
// No rules defined
return "";
}
StringBuilder sebRuleString = new StringBuilder();
foreach (object expression in filterRuleList)
{
if (expression != null)
{
if (sebRuleString.Length == 0)
{
sebRuleString.Append(expression.ToString());
}
else
{
sebRuleString.AppendFormat(";{0}", expression.ToString());
}
}
}
return sebRuleString.ToString();
}
// Filter URL and return if it is allowed or blocked
public URLFilterRuleActions TestURLAllowed(Uri URLToFilter)
{
string URLToFilterString = URLToFilter.ToString();
// By default URLs are blocked
bool allowURL = false;
bool blockURL = false;
/// Apply current filter rules (expressions/actions) to URL
/// Apply prohibited filter expressions
foreach (object expression in prohibitedList)
{
if (expression.GetType().Equals(typeof(Regex)))
{
if (Regex.IsMatch(URLToFilterString, expression.ToString()))
{
blockURL = true;
break;
}
}
if (expression.GetType().Equals(typeof(SEBURLFilterRegexExpression)))
{
if (URLMatchesFilterExpression(URLToFilter, (SEBURLFilterRegexExpression)expression))
{
blockURL = true;
break;
}
}
}
if (blockURL == true)
{
return URLFilterRuleActions.block;
}
/// Apply permitted filter expressions
foreach (object expression in permittedList)
{
if (expression.GetType().Equals(typeof(Regex)))
{
if (Regex.IsMatch(URLToFilterString, expression.ToString()))
{
allowURL = true;
break;
}
}
if (expression.GetType().Equals(typeof(SEBURLFilterRegexExpression)))
{
if (URLMatchesFilterExpression(URLToFilter, (SEBURLFilterRegexExpression)expression))
{
allowURL = true;
break;
}
}
}
// Return URLFilterActionAllow if URL is allowed or
// URLFilterActionUnknown if it's unknown (= it will anyways be blocked)
return allowURL ? URLFilterRuleActions.allow : URLFilterRuleActions.unknown;
}
// Method comparing all components of a passed URL with the filter expression
// and returning YES (= allow or block) if it matches
public bool URLMatchesFilterExpression(Uri URLToFilter, SEBURLFilterRegexExpression filterExpression)
{
Regex filterComponent;
// If a scheme is indicated in the filter expression, it has to match
filterComponent = filterExpression.scheme;
UriBuilder urlToFilterParts = new UriBuilder(URLToFilter);
if (filterComponent != null &&
!Regex.IsMatch(URLToFilter.Scheme, filterComponent.ToString(), RegexOptions.IgnoreCase))
{
// Scheme of the URL to filter doesn't match the one from the filter expression: Exit with matching = NO
return false;
}
string userInfo = URLToFilter.UserInfo;
filterComponent = filterExpression.user;
if (filterComponent != null &&
!Regex.IsMatch(urlToFilterParts.UserName, filterComponent.ToString(), RegexOptions.IgnoreCase))
{
return false;
}
filterComponent = filterExpression.password;
if (filterComponent != null &&
!Regex.IsMatch(urlToFilterParts.Password, filterComponent.ToString(), RegexOptions.IgnoreCase))
{
return false;
}
filterComponent = filterExpression.host;
if (filterComponent != null &&
!Regex.IsMatch(URLToFilter.Host, filterComponent.ToString(), RegexOptions.IgnoreCase))
{
return false;
}
if (filterExpression.port != null && URLToFilter.Port != filterExpression.port)
{
return false;
}
filterComponent = filterExpression.path;
if (filterComponent != null &&
!Regex.IsMatch(URLToFilter.AbsolutePath.TrimEnd(new char[] { '/' }), filterComponent.ToString(), RegexOptions.IgnoreCase))
{
return false;
}
string urlQuery = URLToFilter.GetComponents(UriComponents.Query, UriFormat.Unescaped);
filterComponent = filterExpression.query;
if (filterComponent != null)
{
// If there's a query filter component, then we need to even filter empty URL query strings
// as the filter might either allow some specific queries or no query at all ("?." query filter)
if (urlQuery == null)
{
urlQuery = "";
}
if (!Regex.IsMatch(urlQuery, filterComponent.ToString(), RegexOptions.IgnoreCase))
{
return false;
}
}
string urlFragment = URLToFilter.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
filterComponent = filterExpression.fragment;
if (filterComponent != null &&
!Regex.IsMatch(urlFragment, filterComponent.ToString(), RegexOptions.IgnoreCase))
{
return false;
}
// URL matches the filter expression
return true;
}
}
}