SEBWIN-314: Completed implementation of simplified filter rule.

This commit is contained in:
dbuechel 2019-09-20 11:45:06 +02:00
parent 6d1b282b33
commit d3272814bd
3 changed files with 909 additions and 215 deletions

View file

@ -89,7 +89,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Filters
filterComponent = path;
if (filterComponent != null &&
!Regex.IsMatch(URLToFilter.AbsolutePath.Trim(new char[] { '/' }), filterComponent.ToString(), RegexOptions.IgnoreCase))
!Regex.IsMatch(URLToFilter.AbsolutePath.TrimEnd(new char[] { '/' }), filterComponent.ToString(), RegexOptions.IgnoreCase))
{
return false;
}
@ -404,8 +404,8 @@ namespace SafeExamBrowser.Browser.UnitTests.Filters
this.password = regexMatch.Groups[3].Value;
this.host = regexMatch.Groups[4].Value;
// Treat a special case when a query is interpreted as part of the host address
if (this.host.Contains("?"))
// Treat a special case when a query or fragment is interpreted as part of the host address
if (this.host.Contains("?") || this.host.Contains("#"))
{
string splitURLRegexPattern2 = @"([^\?#]*)?(?:\?([^#]*))?(?:#(.*))?";
Regex splitURLRegex2 = new Regex(splitURLRegexPattern2);
@ -434,7 +434,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Filters
this.port = UInt16.Parse(portNumber);
}
this.path = regexMatch.Groups[6].Value.Trim(new char[] { '/' });
this.path = regexMatch.Groups[6].Value.TrimEnd(new char[] { '/' });
this.query = regexMatch.Groups[7].Value;
this.fragment = regexMatch.Groups[8].Value;
}

View file

@ -15,16 +15,15 @@ namespace SafeExamBrowser.Browser.Filters.Rules
{
internal class SimplifiedRule : IRule
{
private const string URL_DELIMITER_PATTERN = @"(?:([^\:]*)\:\/\/)?(?:([^\:\@]*)(?:\:([^\@]*))?\@)?(?:([^\/\:]*))?(?:\:([0-9\*]*))?([^\?#]*)?(?:\?([^#]*))?(?:#(.*))?";
private const string URL_DELIMITER_PATTERN = @"(?:([^\:]*)\://)?(?:([^\:\@]*)(?:\:([^\@]*))?\@)?(?:([^/\:\?#]*))?(?:\:([0-9\*]*))?([^\?#]*)?(?:\?([^#]*))?(?:#(.*))?";
private Regex fragment;
private Regex host;
private Regex password;
private Regex path;
private int? port;
private Regex query;
private Regex scheme;
private Regex user;
private Regex userInfo;
public FilterResult Result { get; private set; }
@ -41,14 +40,13 @@ namespace SafeExamBrowser.Browser.Filters.Rules
var url = new Uri(request.Url, UriKind.Absolute);
var isMatch = true;
//isMatch &= scheme == default(Regex) || ...;
//isMatch &= user == default(Regex) || ...;
//isMatch &= password == default(Regex) || ...;
isMatch &= scheme == default(Regex) || scheme.IsMatch(url.Scheme);
isMatch &= userInfo == default(Regex) || userInfo.IsMatch(url.UserInfo);
isMatch &= host.IsMatch(url.Host);
isMatch &= !port.HasValue || port == url.Port;
//isMatch &= path == default(Regex) || ...;
//isMatch &= query == default(Regex) || ...;
//isMatch &= fragment == default(Regex) || ...;
isMatch &= path == default(Regex) || path.IsMatch(url.AbsolutePath);
isMatch &= query == default(Regex) || query.IsMatch(url.Query);
isMatch &= fragment == default(Regex) || fragment.IsMatch(url.Fragment);
return isMatch;
}
@ -57,36 +55,58 @@ namespace SafeExamBrowser.Browser.Filters.Rules
{
var match = Regex.Match(expression, URL_DELIMITER_PATTERN);
//ParseScheme(match.Groups[1].Value);
//ParseUser(match.Groups[2].Value);
//ParsePassword(match.Groups[3].Value);
ParseScheme(match.Groups[1].Value);
ParseUserInfo(match.Groups[2].Value, match.Groups[3].Value);
ParseHost(match.Groups[4].Value);
ParsePort(match.Groups[5].Value);
//ParsePath(match.Groups[6].Value);
//ParseQuery(match.Groups[7].Value);
//ParseFragment(match.Groups[8].Value);
ParsePath(match.Groups[6].Value);
ParseQuery(match.Groups[7].Value);
ParseFragment(match.Groups[8].Value);
}
private void ParseScheme(string expression)
{
if (!string.IsNullOrEmpty(expression))
{
expression = Regex.Escape(expression);
expression = ReplaceWildcard(expression);
scheme = Build(expression);
}
}
private void ParseUserInfo(string username, string password)
{
if (!string.IsNullOrEmpty(username))
{
var expression = default(string);
username = Regex.Escape(username);
password = Regex.Escape(password);
expression = string.IsNullOrEmpty(password) ? $@"{username}(:.*)?" : $@"{username}:{password}";
expression = ReplaceWildcard(expression);
userInfo = Build(expression);
}
}
private void ParseHost(string expression)
{
var hasToplevelDomain = Regex.IsMatch(expression, @"\.+");
var hasSubdomain = Regex.IsMatch(expression, @"\.{2,}");
var allowOnlyExactSubdomain = expression.StartsWith(".");
if (allowOnlyExactSubdomain)
{
expression = expression.Substring(1);
}
var matchExactSubdomain = expression.StartsWith(".");
expression = matchExactSubdomain ? expression.Substring(1) : expression;
expression = Regex.Escape(expression);
expression = ReplaceWildcard(expression);
if (!hasToplevelDomain)
{
expression = $@"{expression}(\.[a-z]+)";
expression = $@"{expression}(\.[a-z]+)?";
}
if (!hasSubdomain && !allowOnlyExactSubdomain)
if (!hasSubdomain && !matchExactSubdomain)
{
expression = $@"(.+?\.)*{expression}";
}
@ -102,6 +122,51 @@ namespace SafeExamBrowser.Browser.Filters.Rules
}
}
private void ParsePath(string expression)
{
if (!string.IsNullOrWhiteSpace(expression))
{
expression = Regex.Escape(expression);
expression = ReplaceWildcard(expression);
expression = expression.EndsWith("/") ? $@"{expression}?" : $@"{expression}/?";
path = Build(expression);
}
}
private void ParseQuery(string expression)
{
if (!string.IsNullOrWhiteSpace(expression))
{
var noQueryAllowed = expression == ".";
if (noQueryAllowed)
{
expression = @"\??";
}
else
{
expression = Regex.Escape(expression);
expression = ReplaceWildcard(expression);
expression = $@"\??{expression}";
}
query = Build(expression);
}
}
private void ParseFragment(string expression)
{
if (!string.IsNullOrWhiteSpace(expression))
{
expression = Regex.Escape(expression);
expression = ReplaceWildcard(expression);
expression = $"#?{expression}";
fragment = Build(expression);
}
}
private Regex Build(string expression)
{
return new Regex($"^{expression}$", RegexOptions.IgnoreCase);
@ -109,7 +174,7 @@ namespace SafeExamBrowser.Browser.Filters.Rules
private string ReplaceWildcard(string expression)
{
return expression.Replace(@"\*", ".*?");
return expression.Replace(@"\*", ".*");
}
private void ValidateExpression(string expression)