2
0
Эх сурвалжийг харах

Properly check for item visibility in UserLibraryController

Shadowghost 2 жил өмнө
parent
commit
4ed97a4593

+ 139 - 20
Jellyfin.Api/Controllers/UserLibraryController.cs

@@ -6,6 +6,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Jellyfin.Api.Extensions;
 using Jellyfin.Api.Extensions;
 using Jellyfin.Api.ModelBinders;
 using Jellyfin.Api.ModelBinders;
+using Jellyfin.Data.Entities;
 using Jellyfin.Data.Enums;
 using Jellyfin.Data.Enums;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
@@ -72,7 +73,7 @@ public class UserLibraryController : BaseJellyfinApiController
     /// <param name="userId">User id.</param>
     /// <param name="userId">User id.</param>
     /// <param name="itemId">Item id.</param>
     /// <param name="itemId">Item id.</param>
     /// <response code="200">Item returned.</response>
     /// <response code="200">Item returned.</response>
-    /// <returns>An <see cref="OkResult"/> containing the d item.</returns>
+    /// <returns>An <see cref="OkResult"/> containing the item.</returns>
     [HttpGet("Users/{userId}/Items/{itemId}")]
     [HttpGet("Users/{userId}/Items/{itemId}")]
     [ProducesResponseType(StatusCodes.Status200OK)]
     [ProducesResponseType(StatusCodes.Status200OK)]
     public async Task<ActionResult<BaseItemDto>> GetItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
     public async Task<ActionResult<BaseItemDto>> GetItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
@@ -86,11 +87,19 @@ public class UserLibraryController : BaseJellyfinApiController
         var item = itemId.Equals(default)
         var item = itemId.Equals(default)
             ? _libraryManager.GetUserRootFolder()
             ? _libraryManager.GetUserRootFolder()
             : _libraryManager.GetItemById(itemId);
             : _libraryManager.GetItemById(itemId);
+
         if (item is null)
         if (item is null)
         {
         {
             return NotFound();
             return NotFound();
         }
         }
 
 
+        if (item is not UserRootFolder
+            // Check the item is visible for the user
+            && !item.IsVisible(user))
+        {
+            return Unauthorized($"{user.Username} is not permitted to access item {item.Name}.");
+        }
+
         await RefreshItemOnDemandIfNeeded(item).ConfigureAwait(false);
         await RefreshItemOnDemandIfNeeded(item).ConfigureAwait(false);
 
 
         var dtoOptions = new DtoOptions().AddClientFields(User);
         var dtoOptions = new DtoOptions().AddClientFields(User);
@@ -139,11 +148,19 @@ public class UserLibraryController : BaseJellyfinApiController
         var item = itemId.Equals(default)
         var item = itemId.Equals(default)
             ? _libraryManager.GetUserRootFolder()
             ? _libraryManager.GetUserRootFolder()
             : _libraryManager.GetItemById(itemId);
             : _libraryManager.GetItemById(itemId);
+
         if (item is null)
         if (item is null)
         {
         {
             return NotFound();
             return NotFound();
         }
         }
 
 
+        if (item is not UserRootFolder
+            // Check the item is visible for the user
+            && !item.IsVisible(user))
+        {
+            return Unauthorized($"{user.Username} is not permitted to access item {item.Name}.");
+        }
+
         var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
         var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
         var dtoOptions = new DtoOptions().AddClientFields(User);
         var dtoOptions = new DtoOptions().AddClientFields(User);
         var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray();
         var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray();
@@ -162,7 +179,29 @@ public class UserLibraryController : BaseJellyfinApiController
     [ProducesResponseType(StatusCodes.Status200OK)]
     [ProducesResponseType(StatusCodes.Status200OK)]
     public ActionResult<UserItemDataDto> MarkFavoriteItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
     public ActionResult<UserItemDataDto> MarkFavoriteItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
     {
     {
-        return MarkFavorite(userId, itemId, true);
+        var user = _userManager.GetUserById(userId);
+        if (user is null)
+        {
+            return NotFound();
+        }
+
+        var item = itemId.Equals(default)
+            ? _libraryManager.GetUserRootFolder()
+            : _libraryManager.GetItemById(itemId);
+
+        if (item is null)
+        {
+            return NotFound();
+        }
+
+        if (item is not UserRootFolder
+            // Check the item is visible for the user
+            && !item.IsVisible(user))
+        {
+            return Unauthorized($"{user.Username} is not permitted to access item {item.Name}.");
+        }
+
+        return MarkFavorite(user, item, true);
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -176,7 +215,29 @@ public class UserLibraryController : BaseJellyfinApiController
     [ProducesResponseType(StatusCodes.Status200OK)]
     [ProducesResponseType(StatusCodes.Status200OK)]
     public ActionResult<UserItemDataDto> UnmarkFavoriteItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
     public ActionResult<UserItemDataDto> UnmarkFavoriteItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
     {
     {
-        return MarkFavorite(userId, itemId, false);
+        var user = _userManager.GetUserById(userId);
+        if (user is null)
+        {
+            return NotFound();
+        }
+
+        var item = itemId.Equals(default)
+            ? _libraryManager.GetUserRootFolder()
+            : _libraryManager.GetItemById(itemId);
+
+        if (item is null)
+        {
+            return NotFound();
+        }
+
+        if (item is not UserRootFolder
+            // Check the item is visible for the user
+            && !item.IsVisible(user))
+        {
+            return Unauthorized($"{user.Username} is not permitted to access item {item.Name}.");
+        }
+
+        return MarkFavorite(user, item, false);
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -190,7 +251,29 @@ public class UserLibraryController : BaseJellyfinApiController
     [ProducesResponseType(StatusCodes.Status200OK)]
     [ProducesResponseType(StatusCodes.Status200OK)]
     public ActionResult<UserItemDataDto> DeleteUserItemRating([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
     public ActionResult<UserItemDataDto> DeleteUserItemRating([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
     {
     {
-        return UpdateUserItemRatingInternal(userId, itemId, null);
+        var user = _userManager.GetUserById(userId);
+        if (user is null)
+        {
+            return NotFound();
+        }
+
+        var item = itemId.Equals(default)
+            ? _libraryManager.GetUserRootFolder()
+            : _libraryManager.GetItemById(itemId);
+
+        if (item is null)
+        {
+            return NotFound();
+        }
+
+        if (item is not UserRootFolder
+            // Check the item is visible for the user
+            && !item.IsVisible(user))
+        {
+            return Unauthorized($"{user.Username} is not permitted to access item {item.Name}.");
+        }
+
+        return UpdateUserItemRatingInternal(user, item, null);
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -205,7 +288,29 @@ public class UserLibraryController : BaseJellyfinApiController
     [ProducesResponseType(StatusCodes.Status200OK)]
     [ProducesResponseType(StatusCodes.Status200OK)]
     public ActionResult<UserItemDataDto> UpdateUserItemRating([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId, [FromQuery] bool? likes)
     public ActionResult<UserItemDataDto> UpdateUserItemRating([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId, [FromQuery] bool? likes)
     {
     {
-        return UpdateUserItemRatingInternal(userId, itemId, likes);
+        var user = _userManager.GetUserById(userId);
+        if (user is null)
+        {
+            return NotFound();
+        }
+
+        var item = itemId.Equals(default)
+            ? _libraryManager.GetUserRootFolder()
+            : _libraryManager.GetItemById(itemId);
+
+        if (item is null)
+        {
+            return NotFound();
+        }
+
+        if (item is not UserRootFolder
+            // Check the item is visible for the user
+            && !item.IsVisible(user))
+        {
+            return Unauthorized($"{user.Username} is not permitted to access item {item.Name}.");
+        }
+
+        return UpdateUserItemRatingInternal(user, item, likes);
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -228,13 +333,20 @@ public class UserLibraryController : BaseJellyfinApiController
         var item = itemId.Equals(default)
         var item = itemId.Equals(default)
             ? _libraryManager.GetUserRootFolder()
             ? _libraryManager.GetUserRootFolder()
             : _libraryManager.GetItemById(itemId);
             : _libraryManager.GetItemById(itemId);
+
         if (item is null)
         if (item is null)
         {
         {
             return NotFound();
             return NotFound();
         }
         }
 
 
-        var dtoOptions = new DtoOptions().AddClientFields(User);
+        if (item is not UserRootFolder
+            // Check the item is visible for the user
+            && !item.IsVisible(user))
+        {
+            return Unauthorized($"{user.Username} is not permitted to access item {item.Name}.");
+        }
 
 
+        var dtoOptions = new DtoOptions().AddClientFields(User);
         if (item is IHasTrailers hasTrailers)
         if (item is IHasTrailers hasTrailers)
         {
         {
             var trailers = hasTrailers.LocalTrailers;
             var trailers = hasTrailers.LocalTrailers;
@@ -266,11 +378,19 @@ public class UserLibraryController : BaseJellyfinApiController
         var item = itemId.Equals(default)
         var item = itemId.Equals(default)
             ? _libraryManager.GetUserRootFolder()
             ? _libraryManager.GetUserRootFolder()
             : _libraryManager.GetItemById(itemId);
             : _libraryManager.GetItemById(itemId);
+
         if (item is null)
         if (item is null)
         {
         {
             return NotFound();
             return NotFound();
         }
         }
 
 
+        if (item is not UserRootFolder
+            // Check the item is visible for the user
+            && !item.IsVisible(user))
+        {
+            return Unauthorized($"{user.Username} is not permitted to access item {item.Name}.");
+        }
+
         var dtoOptions = new DtoOptions().AddClientFields(User);
         var dtoOptions = new DtoOptions().AddClientFields(User);
 
 
         return Ok(item
         return Ok(item
@@ -385,15 +505,11 @@ public class UserLibraryController : BaseJellyfinApiController
     /// <summary>
     /// <summary>
     /// Marks the favorite.
     /// Marks the favorite.
     /// </summary>
     /// </summary>
-    /// <param name="userId">The user id.</param>
-    /// <param name="itemId">The item id.</param>
+    /// <param name="user">The user.</param>
+    /// <param name="item">The item.</param>
     /// <param name="isFavorite">if set to <c>true</c> [is favorite].</param>
     /// <param name="isFavorite">if set to <c>true</c> [is favorite].</param>
-    private UserItemDataDto MarkFavorite(Guid userId, Guid itemId, bool isFavorite)
+    private UserItemDataDto MarkFavorite(User user, BaseItem item, bool isFavorite)
     {
     {
-        var user = _userManager.GetUserById(userId);
-
-        var item = itemId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId);
-
         // Get the user data for this item
         // Get the user data for this item
         var data = _userDataRepository.GetUserData(user, item);
         var data = _userDataRepository.GetUserData(user, item);
 
 
@@ -408,15 +524,11 @@ public class UserLibraryController : BaseJellyfinApiController
     /// <summary>
     /// <summary>
     /// Updates the user item rating.
     /// Updates the user item rating.
     /// </summary>
     /// </summary>
-    /// <param name="userId">The user id.</param>
-    /// <param name="itemId">The item id.</param>
+    /// <param name="user">The user.</param>
+    /// <param name="item">The item.</param>
     /// <param name="likes">if set to <c>true</c> [likes].</param>
     /// <param name="likes">if set to <c>true</c> [likes].</param>
-    private UserItemDataDto UpdateUserItemRatingInternal(Guid userId, Guid itemId, bool? likes)
+    private UserItemDataDto UpdateUserItemRatingInternal(User user, BaseItem item, bool? likes)
     {
     {
-        var user = _userManager.GetUserById(userId);
-
-        var item = itemId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId);
-
         // Get the user data for this item
         // Get the user data for this item
         var data = _userDataRepository.GetUserData(user, item);
         var data = _userDataRepository.GetUserData(user, item);
 
 
@@ -455,6 +567,13 @@ public class UserLibraryController : BaseJellyfinApiController
             return NotFound();
             return NotFound();
         }
         }
 
 
+        if (item is not UserRootFolder
+            // Check the item is visible for the user
+            && !item.IsVisible(user))
+        {
+            return Unauthorized($"{user.Username} is not permitted to access item {item.Name}.");
+        }
+
         var result = await _lyricManager.GetLyrics(item).ConfigureAwait(false);
         var result = await _lyricManager.GetLyrics(item).ConfigureAwait(false);
         if (result is not null)
         if (result is not null)
         {
         {