mirror of https://github.com/Radarr/Radarr
parent
564a7554fc
commit
413669dbaa
|
@ -0,0 +1,28 @@
|
|||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore
|
||||
{
|
||||
[TestFixture]
|
||||
public class SortKeyValidationFixture : DbTest
|
||||
{
|
||||
[TestCase("amissingcolumn")]
|
||||
[TestCase("amissingtable.id")]
|
||||
[TestCase("table.table.column")]
|
||||
[TestCase("column; DROP TABLE Commands;--")]
|
||||
public void should_return_false_for_invalid_sort_key(string sortKey)
|
||||
{
|
||||
TableMapping.Mapper.IsValidSortKey(sortKey).Should().BeFalse();
|
||||
}
|
||||
|
||||
[TestCase("Id")]
|
||||
[TestCase("id")]
|
||||
[TestCase("commands.id")]
|
||||
public void should_return_true_for_valid_sort_key(string sortKey)
|
||||
{
|
||||
TableMapping.Mapper.IsValidSortKey(sortKey).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,8 @@ namespace NzbDrone.Core.Datastore
|
|||
{
|
||||
public class TableMapper
|
||||
{
|
||||
private readonly HashSet<string> _allowedOrderBy = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public TableMapper()
|
||||
{
|
||||
IgnoreList = new Dictionary<Type, List<PropertyInfo>>();
|
||||
|
@ -27,12 +29,12 @@ namespace NzbDrone.Core.Datastore
|
|||
|
||||
if (IgnoreList.TryGetValue(type, out var list))
|
||||
{
|
||||
return new ColumnMapper<TEntity>(list, LazyLoadList[type]);
|
||||
return new ColumnMapper<TEntity>(list, LazyLoadList[type], _allowedOrderBy);
|
||||
}
|
||||
|
||||
IgnoreList[type] = new List<PropertyInfo>();
|
||||
LazyLoadList[type] = new List<LazyLoadedProperty>();
|
||||
return new ColumnMapper<TEntity>(IgnoreList[type], LazyLoadList[type]);
|
||||
return new ColumnMapper<TEntity>(IgnoreList[type], LazyLoadList[type], _allowedOrderBy);
|
||||
}
|
||||
|
||||
public List<PropertyInfo> ExcludeProperties(Type x)
|
||||
|
@ -59,6 +61,35 @@ namespace NzbDrone.Core.Datastore
|
|||
{
|
||||
return $"SELECT /**select**/ FROM {TableMap[x]} /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/";
|
||||
}
|
||||
|
||||
public bool IsValidSortKey(string sortKey)
|
||||
{
|
||||
string table = null;
|
||||
|
||||
if (sortKey.Contains('.'))
|
||||
{
|
||||
var split = sortKey.Split('.');
|
||||
if (split.Length != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
table = split[0];
|
||||
sortKey = split[1];
|
||||
}
|
||||
|
||||
if (table != null && !TableMap.Values.Contains(table, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_allowedOrderBy.Contains(sortKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class LazyLoadedProperty
|
||||
|
@ -72,17 +103,20 @@ namespace NzbDrone.Core.Datastore
|
|||
{
|
||||
private readonly List<PropertyInfo> _ignoreList;
|
||||
private readonly List<LazyLoadedProperty> _lazyLoadList;
|
||||
private readonly HashSet<string> _allowedOrderBy;
|
||||
|
||||
public ColumnMapper(List<PropertyInfo> ignoreList, List<LazyLoadedProperty> lazyLoadList)
|
||||
public ColumnMapper(List<PropertyInfo> ignoreList, List<LazyLoadedProperty> lazyLoadList, HashSet<string> allowedOrderBy)
|
||||
{
|
||||
_ignoreList = ignoreList;
|
||||
_lazyLoadList = lazyLoadList;
|
||||
_allowedOrderBy = allowedOrderBy;
|
||||
}
|
||||
|
||||
public ColumnMapper<T> AutoMapPropertiesWhere(Func<PropertyInfo, bool> predicate)
|
||||
{
|
||||
var properties = typeof(T).GetProperties();
|
||||
_ignoreList.AddRange(properties.Where(x => !predicate(x)));
|
||||
_allowedOrderBy.UnionWith(properties.Where(x => predicate(x)).Select(x => x.Name));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,21 @@ namespace Radarr.Http.REST
|
|||
private const string ROOT_ROUTE = "/";
|
||||
private const string ID_ROUTE = @"/(?<id>[\d]{1,10})";
|
||||
|
||||
// See src/Radarr.Api.V3/Queue/QueueModule.cs
|
||||
private static readonly HashSet<string> VALID_SORT_KEYS = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"timeleft",
|
||||
"estimatedCompletionTime",
|
||||
"protocol",
|
||||
"indexer",
|
||||
"downloadClient",
|
||||
"quality",
|
||||
"languages",
|
||||
"status",
|
||||
"title",
|
||||
"progress"
|
||||
};
|
||||
|
||||
private readonly HashSet<string> _excludedKeys = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
"page",
|
||||
|
@ -292,7 +307,15 @@ namespace Radarr.Http.REST
|
|||
|
||||
if (Request.Query.SortKey != null)
|
||||
{
|
||||
pagingResource.SortKey = Request.Query.SortKey.ToString();
|
||||
var sortKey = Request.Query.SortKey.ToString();
|
||||
|
||||
if (!VALID_SORT_KEYS.Contains(sortKey) &&
|
||||
!TableMapping.Mapper.IsValidSortKey(sortKey))
|
||||
{
|
||||
throw new BadRequestException($"Invalid sort key {sortKey}");
|
||||
}
|
||||
|
||||
pagingResource.SortKey = sortKey;
|
||||
|
||||
// For backwards compatibility with v2
|
||||
if (Request.Query.SortDir != null)
|
||||
|
|
Loading…
Reference in New Issue