From fca8c36156da1d9591483a08beddd115c3cb2c31 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sat, 21 Sep 2024 20:12:01 +0300 Subject: [PATCH] Guard against using invalid sort keys --- .../ImportListExclusions.tsx | 2 +- frontend/src/Store/Actions/systemActions.js | 1 - .../Blocklist/BlocklistController.cs | 13 ++++++++++- .../History/HistoryController.cs | 9 +++++++- .../ImportListExclusionController.cs | 11 +++++++++- src/Sonarr.Api.V3/Logs/LogController.cs | 8 ++++++- src/Sonarr.Api.V3/Queue/QueueController.cs | 2 +- src/Sonarr.Api.V3/Wanted/CutoffController.cs | 18 +++++++++------ src/Sonarr.Api.V3/Wanted/MissingController.cs | 18 +++++++++------ src/Sonarr.Http/PagingResource.cs | 22 +++++++++++-------- 10 files changed, 74 insertions(+), 30 deletions(-) diff --git a/frontend/src/Settings/ImportLists/ImportListExclusions/ImportListExclusions.tsx b/frontend/src/Settings/ImportLists/ImportListExclusions/ImportListExclusions.tsx index a93ecda3c..e51ef316f 100644 --- a/frontend/src/Settings/ImportLists/ImportListExclusions/ImportListExclusions.tsx +++ b/frontend/src/Settings/ImportLists/ImportListExclusions/ImportListExclusions.tsx @@ -48,7 +48,7 @@ const COLUMNS: Column[] = [ isSortable: true, }, { - name: 'tvdbid', + name: 'tvdbId', label: () => translate('TvdbId'), isVisible: true, isSortable: true, diff --git a/frontend/src/Store/Actions/systemActions.js b/frontend/src/Store/Actions/systemActions.js index 0f2410846..2c53bda7b 100644 --- a/frontend/src/Store/Actions/systemActions.js +++ b/frontend/src/Store/Actions/systemActions.js @@ -110,7 +110,6 @@ export const defaultState = { { name: 'actions', columnLabel: () => translate('Actions'), - isSortable: true, isVisible: true, isModifiable: false } diff --git a/src/Sonarr.Api.V3/Blocklist/BlocklistController.cs b/src/Sonarr.Api.V3/Blocklist/BlocklistController.cs index c1f69974b..d29b1a86e 100644 --- a/src/Sonarr.Api.V3/Blocklist/BlocklistController.cs +++ b/src/Sonarr.Api.V3/Blocklist/BlocklistController.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc; using NzbDrone.Core.Blocklisting; @@ -28,7 +30,16 @@ public BlocklistController(IBlocklistService blocklistService, public PagingResource GetBlocklist([FromQuery] PagingRequestResource paging, [FromQuery] int[] seriesIds = null, [FromQuery] DownloadProtocol[] protocols = null) { var pagingResource = new PagingResource(paging); - var pagingSpec = pagingResource.MapToPagingSpec("date", SortDirection.Descending); + var pagingSpec = pagingResource.MapToPagingSpec( + new HashSet(StringComparer.OrdinalIgnoreCase) + { + "series.sortTitle", + "sourceTitle", + "date", + "indexer" + }, + "date", + SortDirection.Descending); if (seriesIds?.Any() == true) { diff --git a/src/Sonarr.Api.V3/History/HistoryController.cs b/src/Sonarr.Api.V3/History/HistoryController.cs index 02eae491a..b0810113e 100644 --- a/src/Sonarr.Api.V3/History/HistoryController.cs +++ b/src/Sonarr.Api.V3/History/HistoryController.cs @@ -65,7 +65,14 @@ protected HistoryResource MapToResource(EpisodeHistory model, bool includeSeries public PagingResource GetHistory([FromQuery] PagingRequestResource paging, bool includeSeries, bool includeEpisode, [FromQuery(Name = "eventType")] int[] eventTypes, int? episodeId, string downloadId, [FromQuery] int[] seriesIds = null, [FromQuery] int[] languages = null, [FromQuery] int[] quality = null) { var pagingResource = new PagingResource(paging); - var pagingSpec = pagingResource.MapToPagingSpec("date", SortDirection.Descending); + var pagingSpec = pagingResource.MapToPagingSpec( + new HashSet(StringComparer.OrdinalIgnoreCase) + { + "series.sortTitle", + "date" + }, + "date", + SortDirection.Descending); if (eventTypes != null && eventTypes.Any()) { diff --git a/src/Sonarr.Api.V3/ImportLists/ImportListExclusionController.cs b/src/Sonarr.Api.V3/ImportLists/ImportListExclusionController.cs index c48604bc8..30bd035b4 100644 --- a/src/Sonarr.Api.V3/ImportLists/ImportListExclusionController.cs +++ b/src/Sonarr.Api.V3/ImportLists/ImportListExclusionController.cs @@ -3,6 +3,7 @@ using System.Linq; using FluentValidation; using Microsoft.AspNetCore.Mvc; +using NzbDrone.Core.Datastore; using NzbDrone.Core.ImportLists.Exclusions; using Sonarr.Http; using Sonarr.Http.Extensions; @@ -46,7 +47,15 @@ public List GetImportListExclusions() public PagingResource GetImportListExclusionsPaged([FromQuery] PagingRequestResource paging) { var pagingResource = new PagingResource(paging); - var pageSpec = pagingResource.MapToPagingSpec(); + var pageSpec = pagingResource.MapToPagingSpec( + new HashSet(StringComparer.OrdinalIgnoreCase) + { + "id", + "tvdbId", + "title" + }, + "id", + SortDirection.Descending); return pageSpec.ApplyToPage(_importListExclusionService.Paged, ImportListExclusionResourceMapper.ToResource); } diff --git a/src/Sonarr.Api.V3/Logs/LogController.cs b/src/Sonarr.Api.V3/Logs/LogController.cs index ba8021a42..ba4ff7dcf 100644 --- a/src/Sonarr.Api.V3/Logs/LogController.cs +++ b/src/Sonarr.Api.V3/Logs/LogController.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; @@ -29,7 +31,11 @@ public PagingResource GetLogs([FromQuery] PagingRequestResource pag } var pagingResource = new PagingResource(paging); - var pageSpec = pagingResource.MapToPagingSpec(); + var pageSpec = pagingResource.MapToPagingSpec(new HashSet(StringComparer.OrdinalIgnoreCase) + { + "id", + "time" + }); if (pageSpec.SortKey == "time") { diff --git a/src/Sonarr.Api.V3/Queue/QueueController.cs b/src/Sonarr.Api.V3/Queue/QueueController.cs index 2e74dec94..34315de1e 100644 --- a/src/Sonarr.Api.V3/Queue/QueueController.cs +++ b/src/Sonarr.Api.V3/Queue/QueueController.cs @@ -139,7 +139,7 @@ public object RemoveMany([FromBody] QueueBulkResource resource, [FromQuery] bool public PagingResource GetQueue([FromQuery] PagingRequestResource paging, bool includeUnknownSeriesItems = false, bool includeSeries = false, bool includeEpisode = false, [FromQuery] int[] seriesIds = null, DownloadProtocol? protocol = null, [FromQuery] int[] languages = null, int? quality = null) { var pagingResource = new PagingResource(paging); - var pagingSpec = pagingResource.MapToPagingSpec("timeleft", SortDirection.Ascending); + var pagingSpec = pagingResource.MapToPagingSpec(null, "timeleft", SortDirection.Ascending); return pagingSpec.ApplyToPage((spec) => GetQueue(spec, seriesIds?.ToHashSet(), protocol, languages?.ToHashSet(), quality, includeUnknownSeriesItems), (q) => MapToResource(q, includeSeries, includeEpisode)); } diff --git a/src/Sonarr.Api.V3/Wanted/CutoffController.cs b/src/Sonarr.Api.V3/Wanted/CutoffController.cs index 22be80366..8da4dc597 100644 --- a/src/Sonarr.Api.V3/Wanted/CutoffController.cs +++ b/src/Sonarr.Api.V3/Wanted/CutoffController.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using NzbDrone.Core.CustomFormats; using NzbDrone.Core.Datastore; @@ -31,13 +33,15 @@ public CutoffController(IEpisodeCutoffService episodeCutoffService, public PagingResource GetCutoffUnmetEpisodes([FromQuery] PagingRequestResource paging, bool includeSeries = false, bool includeEpisodeFile = false, bool includeImages = false, bool monitored = true) { var pagingResource = new PagingResource(paging); - var pagingSpec = new PagingSpec - { - Page = pagingResource.Page, - PageSize = pagingResource.PageSize, - SortKey = pagingResource.SortKey, - SortDirection = pagingResource.SortDirection - }; + var pagingSpec = pagingResource.MapToPagingSpec( + new HashSet(StringComparer.OrdinalIgnoreCase) + { + "series.sortTitle", + "episodes.airDateUtc", + "episodes.lastSearchTime" + }, + "episodes.airDateUtc", + SortDirection.Ascending); if (monitored) { diff --git a/src/Sonarr.Api.V3/Wanted/MissingController.cs b/src/Sonarr.Api.V3/Wanted/MissingController.cs index f7444f7a3..2c05025c6 100644 --- a/src/Sonarr.Api.V3/Wanted/MissingController.cs +++ b/src/Sonarr.Api.V3/Wanted/MissingController.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using NzbDrone.Core.CustomFormats; using NzbDrone.Core.Datastore; @@ -27,13 +29,15 @@ public MissingController(IEpisodeService episodeService, public PagingResource GetMissingEpisodes([FromQuery] PagingRequestResource paging, bool includeSeries = false, bool includeImages = false, bool monitored = true) { var pagingResource = new PagingResource(paging); - var pagingSpec = new PagingSpec - { - Page = pagingResource.Page, - PageSize = pagingResource.PageSize, - SortKey = pagingResource.SortKey, - SortDirection = pagingResource.SortDirection - }; + var pagingSpec = pagingResource.MapToPagingSpec( + new HashSet(StringComparer.OrdinalIgnoreCase) + { + "series.sortTitle", + "episodes.airDateUtc", + "episodes.lastSearchTime" + }, + "episodes.airDateUtc", + SortDirection.Ascending); if (monitored) { diff --git a/src/Sonarr.Http/PagingResource.cs b/src/Sonarr.Http/PagingResource.cs index 64123e66a..f29c21a3f 100644 --- a/src/Sonarr.Http/PagingResource.cs +++ b/src/Sonarr.Http/PagingResource.cs @@ -38,7 +38,11 @@ public PagingResource(PagingRequestResource requestResource) public static class PagingResourceMapper { - public static PagingSpec MapToPagingSpec(this PagingResource pagingResource, string defaultSortKey = "Id", SortDirection defaultSortDirection = SortDirection.Ascending) + public static PagingSpec MapToPagingSpec( + this PagingResource pagingResource, + HashSet allowedSortKeys, + string defaultSortKey = "id", + SortDirection defaultSortDirection = SortDirection.Ascending) { var pagingSpec = new PagingSpec { @@ -48,15 +52,15 @@ public static PagingSpec MapToPagingSpec(this PagingR SortDirection = pagingResource.SortDirection, }; - if (pagingResource.SortKey == null) - { - pagingSpec.SortKey = defaultSortKey; + pagingSpec.SortKey = pagingResource.SortKey != null && + allowedSortKeys is { Count: > 0 } && + allowedSortKeys.Contains(pagingResource.SortKey) + ? pagingResource.SortKey + : defaultSortKey; - if (pagingResource.SortDirection == SortDirection.Default) - { - pagingSpec.SortDirection = defaultSortDirection; - } - } + pagingSpec.SortDirection = pagingResource.SortDirection == SortDirection.Default + ? defaultSortDirection + : pagingResource.SortDirection; return pagingSpec; }