fix(permissions): 🐛 Improved the security around the role "Manage Own Requests" (#4397)

* Secure ManageOwnRequests API paths

Fixes #4391

* Hide delete request option if user is not allowed

* Refactor CheckOwnRequests

* Fix deleteRequest test

* Improve performance and clean up code

* Fix manageOwnRequests check

* Refactor CheckCanManageRequest
This commit is contained in:
sephrat 2021-11-11 11:21:44 +01:00 committed by GitHub
parent 4410790bc0
commit 334a32bca4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 106 additions and 36 deletions

View file

@ -78,6 +78,32 @@ namespace Ombi.Core.Engine
return _dbTv;
}
protected async Task<RequestEngineResult> CheckCanManageRequest(BaseRequest request) {
var errorResult = new RequestEngineResult {
Result = false,
ErrorCode = ErrorCode.NoPermissions
};
var successResult = new RequestEngineResult { Result = true };
// Admins can always manage requests
var isAdmin = await IsInRole(OmbiRoles.PowerUser) || await IsInRole(OmbiRoles.Admin);
if (isAdmin) {
return successResult;
}
// Users with 'ManageOwnRequests' can only manage their own requests
var canManageOwnRequests = await IsInRole(OmbiRoles.ManageOwnRequests);
if (!canManageOwnRequests) {
return errorResult;
}
var isRequestedBySameUser = ( await GetUser() ).Id == request.RequestedUser?.Id;
if (isRequestedBySameUser) {
return successResult;
}
return errorResult;
}
public RequestCountModel RequestCount()
{
var movieQuery = MovieRepository.GetAll();

View file

@ -18,7 +18,7 @@ namespace Ombi.Core.Engine
Task<int> GetTotal();
Task<RequestEngineResult> MarkAvailable(int modelId);
Task<RequestEngineResult> MarkUnavailable(int modelId);
Task RemoveAlbumRequest(int requestId);
Task<RequestEngineResult> RemoveAlbumRequest(int requestId);
Task<RequestEngineResult> RequestAlbum(MusicAlbumRequestViewModel model);
Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search);
Task<bool> UserHasRequest(string userId);

View file

@ -14,7 +14,7 @@ namespace Ombi.Core.Engine.Interfaces
Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search);
Task<RequestEngineResult> RequestCollection(int collectionId, CancellationToken cancellationToken);
Task RemoveMovieRequest(int requestId);
Task<RequestEngineResult> RemoveMovieRequest(int requestId);
Task RemoveAllMovieRequests();
Task<MovieRequests> GetRequest(int requestId);
Task<MovieRequests> UpdateMovieRequest(MovieRequests request);

View file

@ -20,7 +20,7 @@ namespace Ombi.Core.Engine.Interfaces
Task<TvRequests> UpdateTvRequest(TvRequests request);
Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId);
Task<ChildRequests> UpdateChildRequest(ChildRequests request);
Task RemoveTvChild(int requestId);
Task<RequestEngineResult> RemoveTvChild(int requestId);
Task<RequestEngineResult> ApproveChildRequest(int id);
Task<IEnumerable<TvRequests>> GetRequestsLite();
Task UpdateQualityProfile(int requestId, int profileId);

View file

@ -654,11 +654,20 @@ namespace Ombi.Core.Engine
/// </summary>
/// <param name="requestId">The request identifier.</param>
/// <returns></returns>
public async Task RemoveMovieRequest(int requestId)
public async Task<RequestEngineResult> RemoveMovieRequest(int requestId)
{
var request = await MovieRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId);
var result = await CheckCanManageRequest(request);
if (result.IsError)
return result;
await MovieRepository.Delete(request);
await _mediaCacheService.Purge();
return new RequestEngineResult
{
Result = true,
};
}
public async Task RemoveAllMovieRequests()

View file

@ -404,10 +404,20 @@ namespace Ombi.Core.Engine
/// </summary>
/// <param name="requestId">The request identifier.</param>
/// <returns></returns>
public async Task RemoveAlbumRequest(int requestId)
public async Task<RequestEngineResult> RemoveAlbumRequest(int requestId)
{
var request = await MusicRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId);
var result = await CheckCanManageRequest(request);
if (result.IsError)
return result;
await MusicRepository.Delete(request);
return new RequestEngineResult
{
Result = true,
};
}
public async Task<bool> UserHasRequest(string userId)

View file

@ -7,7 +7,7 @@ namespace Ombi.Core.Engine
{
public bool Result { get; set; }
public string Message { get; set; }
public bool IsError => !string.IsNullOrEmpty(ErrorMessage);
public bool IsError => ( !string.IsNullOrEmpty(ErrorMessage) || ErrorCode != null );
public string ErrorMessage { get; set; }
public ErrorCode? ErrorCode { get; set; }
public int RequestId { get; set; }

View file

@ -749,10 +749,14 @@ namespace Ombi.Core.Engine
return request;
}
public async Task RemoveTvChild(int requestId)
public async Task<RequestEngineResult> RemoveTvChild(int requestId)
{
var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId);
var result = await CheckCanManageRequest(request);
if (result.IsError)
return result;
TvRepository.Db.ChildRequests.Remove(request);
var all = TvRepository.Db.TvRequests.Include(x => x.ChildRequests);
var parent = all.FirstOrDefault(x => x.Id == request.ParentRequestId);
@ -766,6 +770,11 @@ namespace Ombi.Core.Engine
await TvRepository.Db.SaveChangesAsync();
await _mediaCacheService.Purge();
return new RequestEngineResult
{
Result = true,
};
}
public async Task RemoveTvRequest(int requestId)