Smart Filter Encoding Fix (#2387)

This commit is contained in:
Joe Milazzo 2023-11-02 08:35:43 -05:00 committed by GitHub
parent b6d4938e22
commit 9894a2623c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
133 changed files with 677 additions and 471 deletions

View file

@ -5,14 +5,24 @@ using System.Web;
using API.DTOs.Filtering;
using API.DTOs.Filtering.v2;
#nullable enable
namespace API.Helpers;
public static class SmartFilterHelper
{
private const string SortOptionsKey = "sortOptions=";
private const string NameKey = "name=";
private const string SortFieldKey = "sortField=";
private const string IsAscendingKey = "isAscending=";
private const string StatementsKey = "stmts=";
private const string LimitToKey = "limitTo=";
private const string CombinationKey = "combination=";
private const string StatementComparisonKey = "comparison=";
private const string StatementFieldKey = "field=";
private const string StatementValueKey = "value=";
public const string StatementSeparator = "\ufffd";
public const string InnerStatementSeparator = "¦";
public static FilterV2Dto Decode(string? encodedFilter)
{
@ -21,7 +31,7 @@ public static class SmartFilterHelper
return new FilterV2Dto(); // Create a default filter if the input is empty
}
string[] parts = encodedFilter.Split('&');
var parts = encodedFilter.Split('&');
var filter = new FilterV2Dto();
foreach (var part in parts)
@ -42,7 +52,7 @@ public static class SmartFilterHelper
{
filter.Statements = DecodeFilterStatementDtos(part.Substring(StatementsKey.Length));
}
else if (part.StartsWith("name="))
else if (part.StartsWith(NameKey))
{
filter.Name = HttpUtility.UrlDecode(part.Substring(5));
}
@ -51,7 +61,7 @@ public static class SmartFilterHelper
return filter;
}
public static string Encode(FilterV2Dto filter)
public static string Encode(FilterV2Dto? filter)
{
if (filter == null)
return string.Empty;
@ -59,50 +69,50 @@ public static class SmartFilterHelper
var encodedStatements = EncodeFilterStatementDtos(filter.Statements);
var encodedSortOptions = filter.SortOptions != null
? $"{SortOptionsKey}{EncodeSortOptions(filter.SortOptions)}"
: "";
: string.Empty;
var encodedLimitTo = $"{LimitToKey}{filter.LimitTo}";
return $"{EncodeName(filter.Name)}{encodedStatements}&{encodedSortOptions}&{encodedLimitTo}&{CombinationKey}{(int) filter.Combination}";
}
private static string EncodeName(string name)
private static string EncodeName(string? name)
{
return string.IsNullOrWhiteSpace(name) ? string.Empty : $"name={HttpUtility.UrlEncode(name)}&";
return string.IsNullOrWhiteSpace(name) ? string.Empty : $"{NameKey}{Uri.EscapeDataString(name)}&";
}
private static string EncodeSortOptions(SortOptions sortOptions)
{
return Uri.EscapeDataString($"sortField={(int) sortOptions.SortField},isAscending={sortOptions.IsAscending}");
return Uri.EscapeDataString($"{SortFieldKey}{(int) sortOptions.SortField}{InnerStatementSeparator}{IsAscendingKey}{sortOptions.IsAscending}");
}
private static string EncodeFilterStatementDtos(ICollection<FilterStatementDto> statements)
private static string EncodeFilterStatementDtos(ICollection<FilterStatementDto>? statements)
{
if (statements == null || statements.Count == 0)
return string.Empty;
var encodedStatements = StatementsKey + Uri.EscapeDataString(string.Join(",", statements.Select(EncodeFilterStatementDto)));
var encodedStatements = StatementsKey + Uri.EscapeDataString(string.Join(StatementSeparator, statements.Select(EncodeFilterStatementDto)));
return encodedStatements;
}
private static string EncodeFilterStatementDto(FilterStatementDto statement)
{
var encodedComparison = $"comparison={(int) statement.Comparison}";
var encodedField = $"field={(int) statement.Field}";
var encodedValue = $"value={Uri.EscapeDataString(statement.Value)}";
return Uri.EscapeDataString($"{encodedComparison},{encodedField},{encodedValue}");
var encodedComparison = $"{StatementComparisonKey}{(int) statement.Comparison}";
var encodedField = $"{StatementFieldKey}{(int) statement.Field}";
var encodedValue = $"{StatementValueKey}{Uri.EscapeDataString(statement.Value)}";
return Uri.EscapeDataString($"{encodedComparison}{InnerStatementSeparator}{encodedField}{InnerStatementSeparator}{encodedValue}");
}
private static List<FilterStatementDto> DecodeFilterStatementDtos(string encodedStatements)
{
encodedStatements = HttpUtility.UrlDecode(encodedStatements);
string[] statementStrings = encodedStatements.Split(',');
var statementStrings = Uri.UnescapeDataString(encodedStatements).Split(StatementSeparator);
var statements = new List<FilterStatementDto>();
foreach (var statementString in statementStrings)
{
var parts = statementString.Split('&');
var parts = Uri.UnescapeDataString(statementString).Split(InnerStatementSeparator);
if (parts.Length < 3)
continue;
@ -110,7 +120,7 @@ public static class SmartFilterHelper
{
Comparison = Enum.Parse<FilterComparison>(parts[0].Split("=")[1]),
Field = Enum.Parse<FilterField>(parts[1].Split("=")[1]),
Value = HttpUtility.UrlDecode(parts[2].Split("=")[1])
Value = Uri.UnescapeDataString(parts[2].Split("=")[1])
});
}
@ -119,22 +129,22 @@ public static class SmartFilterHelper
private static SortOptions DecodeSortOptions(string encodedSortOptions)
{
string[] parts = encodedSortOptions.Split(',');
var sortFieldPart = parts.FirstOrDefault(part => part.StartsWith("sortField="));
var isAscendingPart = parts.FirstOrDefault(part => part.StartsWith("isAscending="));
var parts = Uri.UnescapeDataString(encodedSortOptions).Split(InnerStatementSeparator);
var sortFieldPart = parts.FirstOrDefault(part => part.StartsWith(SortFieldKey));
var isAscendingPart = parts.FirstOrDefault(part => part.StartsWith(IsAscendingKey));
var isAscending = isAscendingPart?.Substring(11).Equals("true", StringComparison.OrdinalIgnoreCase) ?? false;
if (sortFieldPart != null)
if (sortFieldPart == null)
{
var sortField = Enum.Parse<SortField>(sortFieldPart.Split("=")[1]);
return new SortOptions
{
SortField = sortField,
IsAscending = isAscending
};
return new SortOptions();
}
return null;
var sortField = Enum.Parse<SortField>(sortFieldPart.Split("=")[1]);
return new SortOptions
{
SortField = sortField,
IsAscending = isAscending
};
}
}