Validate requested user id (#8812)

This commit is contained in:
Cody Robibero 2023-02-17 15:16:08 -07:00 committed by GitHub
parent 9979b346ea
commit a527034ebe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 232 additions and 70 deletions

View File

@ -118,6 +118,7 @@ public class ArtistsController : BaseJellyfinApiController
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User) .AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@ -125,7 +126,7 @@ public class ArtistsController : BaseJellyfinApiController
User? user = null; User? user = null;
BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId); BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);
if (userId.HasValue && !userId.Equals(default)) if (!userId.Value.Equals(default))
{ {
user = _userManager.GetUserById(userId.Value); user = _userManager.GetUserById(userId.Value);
} }
@ -321,6 +322,7 @@ public class ArtistsController : BaseJellyfinApiController
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User) .AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@ -328,7 +330,7 @@ public class ArtistsController : BaseJellyfinApiController
User? user = null; User? user = null;
BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId); BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);
if (userId.HasValue && !userId.Equals(default)) if (!userId.Value.Equals(default))
{ {
user = _userManager.GetUserById(userId.Value); user = _userManager.GetUserById(userId.Value);
} }
@ -462,11 +464,12 @@ public class ArtistsController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<BaseItemDto> GetArtistByName([FromRoute, Required] string name, [FromQuery] Guid? userId) public ActionResult<BaseItemDto> GetArtistByName([FromRoute, Required] string name, [FromQuery] Guid? userId)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions().AddClientFields(User); var dtoOptions = new DtoOptions().AddClientFields(User);
var item = _libraryManager.GetArtist(name, dtoOptions); var item = _libraryManager.GetArtist(name, dtoOptions);
if (userId.HasValue && !userId.Value.Equals(default)) if (!userId.Value.Equals(default))
{ {
var user = _userManager.GetUserById(userId.Value); var user = _userManager.GetUserById(userId.Value);

View File

@ -60,11 +60,12 @@ public class ChannelsController : BaseJellyfinApiController
[FromQuery] bool? supportsMediaDeletion, [FromQuery] bool? supportsMediaDeletion,
[FromQuery] bool? isFavorite) [FromQuery] bool? isFavorite)
{ {
userId = RequestHelpers.GetUserId(User, userId);
return _channelManager.GetChannels(new ChannelQuery return _channelManager.GetChannels(new ChannelQuery
{ {
Limit = limit, Limit = limit,
StartIndex = startIndex, StartIndex = startIndex,
UserId = userId ?? Guid.Empty, UserId = userId.Value,
SupportsLatestItems = supportsLatestItems, SupportsLatestItems = supportsLatestItems,
SupportsMediaDeletion = supportsMediaDeletion, SupportsMediaDeletion = supportsMediaDeletion,
IsFavorite = isFavorite IsFavorite = isFavorite
@ -124,7 +125,8 @@ public class ChannelsController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -198,7 +200,8 @@ public class ChannelsController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] channelIds) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] channelIds)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);

View File

@ -2,6 +2,7 @@ using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers;
using Jellyfin.Data.Dtos; using Jellyfin.Data.Dtos;
using Jellyfin.Data.Entities.Security; using Jellyfin.Data.Entities.Security;
using Jellyfin.Data.Queries; using Jellyfin.Data.Queries;
@ -48,6 +49,7 @@ public class DevicesController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<QueryResult<DeviceInfo>>> GetDevices([FromQuery] bool? supportsSync, [FromQuery] Guid? userId) public async Task<ActionResult<QueryResult<DeviceInfo>>> GetDevices([FromQuery] bool? supportsSync, [FromQuery] Guid? userId)
{ {
userId = RequestHelpers.GetUserId(User, userId);
return await _deviceManager.GetDevicesForUser(userId, supportsSync).ConfigureAwait(false); return await _deviceManager.GetDevicesForUser(userId, supportsSync).ConfigureAwait(false);
} }

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
@ -51,7 +53,8 @@ public class FilterController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -143,7 +146,8 @@ public class FilterController : BaseJellyfinApiController
[FromQuery] bool? isSeries, [FromQuery] bool? isSeries,
[FromQuery] bool? recursive) [FromQuery] bool? recursive)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);

View File

@ -90,11 +90,12 @@ public class GenresController : BaseJellyfinApiController
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User) .AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, false, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, false, imageTypeLimit, enableImageTypes);
User? user = userId is null || userId.Value.Equals(default) User? user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -155,6 +156,7 @@ public class GenresController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<BaseItemDto> GetGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId) public ActionResult<BaseItemDto> GetGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions() var dtoOptions = new DtoOptions()
.AddClientFields(User); .AddClientFields(User);
@ -170,7 +172,7 @@ public class GenresController : BaseJellyfinApiController
item ??= new Genre(); item ??= new Genre();
if (userId is null || userId.Value.Equals(default)) if (userId.Value.Equals(default))
{ {
return _dtoService.GetBaseItemDto(item, dtoOptions); return _dtoService.GetBaseItemDto(item, dtoOptions);
} }

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
@ -74,7 +75,8 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{ {
var item = _libraryManager.GetItemById(id); var item = _libraryManager.GetItemById(id);
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
@ -110,7 +112,8 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{ {
var album = _libraryManager.GetItemById(id); var album = _libraryManager.GetItemById(id);
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
@ -146,7 +149,8 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{ {
var playlist = (Playlist)_libraryManager.GetItemById(id); var playlist = (Playlist)_libraryManager.GetItemById(id);
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
@ -181,7 +185,8 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
@ -217,7 +222,8 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{ {
var item = _libraryManager.GetItemById(id); var item = _libraryManager.GetItemById(id);
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
@ -253,7 +259,8 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{ {
var item = _libraryManager.GetItemById(id); var item = _libraryManager.GetItemById(id);
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
@ -326,7 +333,8 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{ {
var item = _libraryManager.GetItemById(id); var item = _libraryManager.GetItemById(id);
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }

View File

@ -240,7 +240,8 @@ public class ItemsController : BaseJellyfinApiController
{ {
var isApiKey = User.GetIsApiKey(); var isApiKey = User.GetIsApiKey();
// if api key is used (auth.IsApiKey == true), then `user` will be null throughout this method // if api key is used (auth.IsApiKey == true), then `user` will be null throughout this method
var user = !isApiKey && userId.HasValue && !userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = !isApiKey && !userId.Value.Equals(default)
? _userManager.GetUserById(userId.Value) ?? throw new ResourceNotFoundException() ? _userManager.GetUserById(userId.Value) ?? throw new ResourceNotFoundException()
: null; : null;

View File

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Jellyfin.Api.Attributes; using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.LibraryDtos; using Jellyfin.Api.Models.LibraryDtos;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
@ -142,12 +143,13 @@ public class LibraryController : BaseJellyfinApiController
[FromQuery] Guid? userId, [FromQuery] Guid? userId,
[FromQuery] bool inheritFromParent = false) [FromQuery] bool inheritFromParent = false)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var item = itemId.Equals(default) var item = itemId.Equals(default)
? (userId is null || userId.Value.Equals(default) ? (userId.Value.Equals(default)
? _libraryManager.RootFolder ? _libraryManager.RootFolder
: _libraryManager.GetUserRootFolder()) : _libraryManager.GetUserRootFolder())
: _libraryManager.GetItemById(itemId); : _libraryManager.GetItemById(itemId);
@ -208,12 +210,13 @@ public class LibraryController : BaseJellyfinApiController
[FromQuery] Guid? userId, [FromQuery] Guid? userId,
[FromQuery] bool inheritFromParent = false) [FromQuery] bool inheritFromParent = false)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var item = itemId.Equals(default) var item = itemId.Equals(default)
? (userId is null || userId.Value.Equals(default) ? (userId.Value.Equals(default)
? _libraryManager.RootFolder ? _libraryManager.RootFolder
: _libraryManager.GetUserRootFolder()) : _libraryManager.GetUserRootFolder())
: _libraryManager.GetItemById(itemId); : _libraryManager.GetItemById(itemId);
@ -403,7 +406,8 @@ public class LibraryController : BaseJellyfinApiController
[FromQuery] Guid? userId, [FromQuery] Guid? userId,
[FromQuery] bool? isFavorite) [FromQuery] bool? isFavorite)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -437,6 +441,7 @@ public class LibraryController : BaseJellyfinApiController
public ActionResult<IEnumerable<BaseItemDto>> GetAncestors([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId) public ActionResult<IEnumerable<BaseItemDto>> GetAncestors([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId)
{ {
var item = _libraryManager.GetItemById(itemId); var item = _libraryManager.GetItemById(itemId);
userId = RequestHelpers.GetUserId(User, userId);
if (item is null) if (item is null)
{ {
@ -445,7 +450,7 @@ public class LibraryController : BaseJellyfinApiController
var baseItemDtos = new List<BaseItemDto>(); var baseItemDtos = new List<BaseItemDto>();
var user = userId is null || userId.Value.Equals(default) var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -675,8 +680,9 @@ public class LibraryController : BaseJellyfinApiController
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var item = itemId.Equals(default) var item = itemId.Equals(default)
? (userId is null || userId.Value.Equals(default) ? (userId.Value.Equals(default)
? _libraryManager.RootFolder ? _libraryManager.RootFolder
: _libraryManager.GetUserRootFolder()) : _libraryManager.GetUserRootFolder())
: _libraryManager.GetItemById(itemId); : _libraryManager.GetItemById(itemId);
@ -691,7 +697,7 @@ public class LibraryController : BaseJellyfinApiController
return new QueryResult<BaseItemDto>(); return new QueryResult<BaseItemDto>();
} }
var user = userId is null || userId.Value.Equals(default) var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }

View File

@ -153,6 +153,7 @@ public class LiveTvController : BaseJellyfinApiController
[FromQuery] bool enableFavoriteSorting = false, [FromQuery] bool enableFavoriteSorting = false,
[FromQuery] bool addCurrentProgram = true) [FromQuery] bool addCurrentProgram = true)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User) .AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@ -161,7 +162,7 @@ public class LiveTvController : BaseJellyfinApiController
new LiveTvChannelQuery new LiveTvChannelQuery
{ {
ChannelType = type, ChannelType = type,
UserId = userId ?? Guid.Empty, UserId = userId.Value,
StartIndex = startIndex, StartIndex = startIndex,
Limit = limit, Limit = limit,
IsFavorite = isFavorite, IsFavorite = isFavorite,
@ -180,7 +181,7 @@ public class LiveTvController : BaseJellyfinApiController
dtoOptions, dtoOptions,
CancellationToken.None); CancellationToken.None);
var user = userId is null || userId.Value.Equals(default) var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -211,7 +212,8 @@ public class LiveTvController : BaseJellyfinApiController
[Authorize(Policy = Policies.LiveTvAccess)] [Authorize(Policy = Policies.LiveTvAccess)]
public ActionResult<BaseItemDto> GetChannel([FromRoute, Required] Guid channelId, [FromQuery] Guid? userId) public ActionResult<BaseItemDto> GetChannel([FromRoute, Required] Guid channelId, [FromQuery] Guid? userId)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var item = channelId.Equals(default) var item = channelId.Equals(default)
@ -271,6 +273,7 @@ public class LiveTvController : BaseJellyfinApiController
[FromQuery] bool? isLibraryItem, [FromQuery] bool? isLibraryItem,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User) .AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@ -279,7 +282,7 @@ public class LiveTvController : BaseJellyfinApiController
new RecordingQuery new RecordingQuery
{ {
ChannelId = channelId, ChannelId = channelId,
UserId = userId ?? Guid.Empty, UserId = userId.Value,
StartIndex = startIndex, StartIndex = startIndex,
Limit = limit, Limit = limit,
Status = status, Status = status,
@ -382,7 +385,8 @@ public class LiveTvController : BaseJellyfinApiController
[Authorize(Policy = Policies.LiveTvAccess)] [Authorize(Policy = Policies.LiveTvAccess)]
public ActionResult<QueryResult<BaseItemDto>> GetRecordingFolders([FromQuery] Guid? userId) public ActionResult<QueryResult<BaseItemDto>> GetRecordingFolders([FromQuery] Guid? userId)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var folders = _liveTvManager.GetRecordingFolders(user); var folders = _liveTvManager.GetRecordingFolders(user);
@ -404,7 +408,8 @@ public class LiveTvController : BaseJellyfinApiController
[Authorize(Policy = Policies.LiveTvAccess)] [Authorize(Policy = Policies.LiveTvAccess)]
public ActionResult<BaseItemDto> GetRecording([FromRoute, Required] Guid recordingId, [FromQuery] Guid? userId) public ActionResult<BaseItemDto> GetRecording([FromRoute, Required] Guid recordingId, [FromQuery] Guid? userId)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var item = recordingId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(recordingId); var item = recordingId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(recordingId);
@ -560,7 +565,8 @@ public class LiveTvController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -699,7 +705,8 @@ public class LiveTvController : BaseJellyfinApiController
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -737,7 +744,8 @@ public class LiveTvController : BaseJellyfinApiController
[FromRoute, Required] string programId, [FromRoute, Required] string programId,
[FromQuery] Guid? userId) [FromQuery] Guid? userId)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);

View File

@ -132,6 +132,7 @@ public class MediaInfoController : BaseJellyfinApiController
// Copy params from posted body // Copy params from posted body
// TODO clean up when breaking API compatibility. // TODO clean up when breaking API compatibility.
userId ??= playbackInfoDto?.UserId; userId ??= playbackInfoDto?.UserId;
userId = RequestHelpers.GetUserId(User, userId);
maxStreamingBitrate ??= playbackInfoDto?.MaxStreamingBitrate; maxStreamingBitrate ??= playbackInfoDto?.MaxStreamingBitrate;
startTimeTicks ??= playbackInfoDto?.StartTimeTicks; startTimeTicks ??= playbackInfoDto?.StartTimeTicks;
audioStreamIndex ??= playbackInfoDto?.AudioStreamIndex; audioStreamIndex ??= playbackInfoDto?.AudioStreamIndex;
@ -253,10 +254,12 @@ public class MediaInfoController : BaseJellyfinApiController
[FromQuery] bool? enableDirectPlay, [FromQuery] bool? enableDirectPlay,
[FromQuery] bool? enableDirectStream) [FromQuery] bool? enableDirectStream)
{ {
userId ??= openLiveStreamDto?.UserId;
userId = RequestHelpers.GetUserId(User, userId);
var request = new LiveStreamRequest var request = new LiveStreamRequest
{ {
OpenToken = openToken ?? openLiveStreamDto?.OpenToken, OpenToken = openToken ?? openLiveStreamDto?.OpenToken,
UserId = userId ?? openLiveStreamDto?.UserId ?? Guid.Empty, UserId = userId.Value,
PlaySessionId = playSessionId ?? openLiveStreamDto?.PlaySessionId, PlaySessionId = playSessionId ?? openLiveStreamDto?.PlaySessionId,
MaxStreamingBitrate = maxStreamingBitrate ?? openLiveStreamDto?.MaxStreamingBitrate, MaxStreamingBitrate = maxStreamingBitrate ?? openLiveStreamDto?.MaxStreamingBitrate,
StartTimeTicks = startTimeTicks ?? openLiveStreamDto?.StartTimeTicks, StartTimeTicks = startTimeTicks ?? openLiveStreamDto?.StartTimeTicks,

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
@ -67,7 +68,8 @@ public class MoviesController : BaseJellyfinApiController
[FromQuery] int categoryLimit = 5, [FromQuery] int categoryLimit = 5,
[FromQuery] int itemLimit = 8) [FromQuery] int itemLimit = 8)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }

View File

@ -90,11 +90,12 @@ public class MusicGenresController : BaseJellyfinApiController
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User) .AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, false, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, false, imageTypeLimit, enableImageTypes);
User? user = userId is null || userId.Value.Equals(default) User? user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -144,6 +145,7 @@ public class MusicGenresController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<BaseItemDto> GetMusicGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId) public ActionResult<BaseItemDto> GetMusicGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions().AddClientFields(User); var dtoOptions = new DtoOptions().AddClientFields(User);
MusicGenre? item; MusicGenre? item;
@ -162,7 +164,7 @@ public class MusicGenresController : BaseJellyfinApiController
return NotFound(); return NotFound();
} }
if (userId.HasValue && !userId.Value.Equals(default)) if (!userId.Value.Equals(default))
{ {
var user = _userManager.GetUserById(userId.Value); var user = _userManager.GetUserById(userId.Value);

View File

@ -2,6 +2,7 @@ using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
@ -77,11 +78,12 @@ public class PersonsController : BaseJellyfinApiController
[FromQuery] Guid? userId, [FromQuery] Guid? userId,
[FromQuery] bool? enableImages = true) [FromQuery] bool? enableImages = true)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User) .AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
User? user = userId is null || userId.Value.Equals(default) User? user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -117,6 +119,7 @@ public class PersonsController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<BaseItemDto> GetPerson([FromRoute, Required] string name, [FromQuery] Guid? userId) public ActionResult<BaseItemDto> GetPerson([FromRoute, Required] string name, [FromQuery] Guid? userId)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions() var dtoOptions = new DtoOptions()
.AddClientFields(User); .AddClientFields(User);
@ -126,7 +129,7 @@ public class PersonsController : BaseJellyfinApiController
return NotFound(); return NotFound();
} }
if (userId.HasValue && !userId.Value.Equals(default)) if (!userId.Value.Equals(default))
{ {
var user = _userManager.GetUserById(userId.Value); var user = _userManager.GetUserById(userId.Value);
return _dtoService.GetBaseItemDto(item, dtoOptions, user); return _dtoService.GetBaseItemDto(item, dtoOptions, user);

View File

@ -5,6 +5,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Attributes; using Jellyfin.Api.Attributes;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.PlaylistDtos; using Jellyfin.Api.Models.PlaylistDtos;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
@ -81,11 +82,13 @@ public class PlaylistsController : BaseJellyfinApiController
ids = createPlaylistRequest?.Ids ?? Array.Empty<Guid>(); ids = createPlaylistRequest?.Ids ?? Array.Empty<Guid>();
} }
userId ??= createPlaylistRequest?.UserId ?? default;
userId = RequestHelpers.GetUserId(User, userId);
var result = await _playlistManager.CreatePlaylist(new PlaylistCreationRequest var result = await _playlistManager.CreatePlaylist(new PlaylistCreationRequest
{ {
Name = name ?? createPlaylistRequest?.Name, Name = name ?? createPlaylistRequest?.Name,
ItemIdList = ids, ItemIdList = ids,
UserId = userId ?? createPlaylistRequest?.UserId ?? default, UserId = userId.Value,
MediaType = mediaType ?? createPlaylistRequest?.MediaType MediaType = mediaType ?? createPlaylistRequest?.MediaType
}).ConfigureAwait(false); }).ConfigureAwait(false);
@ -107,7 +110,8 @@ public class PlaylistsController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids,
[FromQuery] Guid? userId) [FromQuery] Guid? userId)
{ {
await _playlistManager.AddToPlaylistAsync(playlistId, ids, userId ?? Guid.Empty).ConfigureAwait(false); userId = RequestHelpers.GetUserId(User, userId);
await _playlistManager.AddToPlaylistAsync(playlistId, ids, userId.Value).ConfigureAwait(false);
return NoContent(); return NoContent();
} }

View File

@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
@ -116,17 +117,11 @@ public class QuickConnectController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<bool>> AuthorizeQuickConnect([FromQuery, Required] string code, [FromQuery] Guid? userId = null) public async Task<ActionResult<bool>> AuthorizeQuickConnect([FromQuery, Required] string code, [FromQuery] Guid? userId = null)
{ {
var currentUserId = User.GetUserId(); userId = RequestHelpers.GetUserId(User, userId);
var actualUserId = userId ?? currentUserId;
if (actualUserId.Equals(default) || (!userId.Equals(currentUserId) && !User.IsInRole(UserRoles.Administrator)))
{
return Forbid("Unknown user id");
}
try try
{ {
return await _quickConnect.AuthorizeRequest(actualUserId, code).ConfigureAwait(false); return await _quickConnect.AuthorizeRequest(userId.Value, code).ConfigureAwait(false);
} }
catch (AuthenticationException) catch (AuthenticationException)
{ {

View File

@ -3,6 +3,8 @@ using System.ComponentModel;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
@ -98,6 +100,7 @@ public class SearchController : BaseJellyfinApiController
[FromQuery] bool includeStudios = true, [FromQuery] bool includeStudios = true,
[FromQuery] bool includeArtists = true) [FromQuery] bool includeArtists = true)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var result = _searchEngine.GetSearchHints(new SearchQuery var result = _searchEngine.GetSearchHints(new SearchQuery
{ {
Limit = limit, Limit = limit,
@ -108,7 +111,7 @@ public class SearchController : BaseJellyfinApiController
IncludePeople = includePeople, IncludePeople = includePeople,
IncludeStudios = includeStudios, IncludeStudios = includeStudios,
StartIndex = startIndex, StartIndex = startIndex,
UserId = userId ?? Guid.Empty, UserId = userId.Value,
IncludeItemTypes = includeItemTypes, IncludeItemTypes = includeItemTypes,
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = excludeItemTypes,
MediaTypes = mediaTypes, MediaTypes = mediaTypes,

View File

@ -86,11 +86,12 @@ public class StudiosController : BaseJellyfinApiController
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User) .AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
User? user = userId is null || userId.Value.Equals(default) User? user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -139,10 +140,11 @@ public class StudiosController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<BaseItemDto> GetStudio([FromRoute, Required] string name, [FromQuery] Guid? userId) public ActionResult<BaseItemDto> GetStudio([FromRoute, Required] string name, [FromQuery] Guid? userId)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions().AddClientFields(User); var dtoOptions = new DtoOptions().AddClientFields(User);
var item = _libraryManager.GetStudio(name); var item = _libraryManager.GetStudio(name);
if (userId.HasValue && !userId.Equals(default)) if (!userId.Equals(default))
{ {
var user = _userManager.GetUserById(userId.Value); var user = _userManager.GetUserById(userId.Value);

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
@ -87,6 +88,7 @@ public class TvShowsController : BaseJellyfinApiController
[FromQuery] bool disableFirstEpisode = false, [FromQuery] bool disableFirstEpisode = false,
[FromQuery] bool enableRewatching = false) [FromQuery] bool enableRewatching = false)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var options = new DtoOptions { Fields = fields } var options = new DtoOptions { Fields = fields }
.AddClientFields(User) .AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@ -98,7 +100,7 @@ public class TvShowsController : BaseJellyfinApiController
ParentId = parentId, ParentId = parentId,
SeriesId = seriesId, SeriesId = seriesId,
StartIndex = startIndex, StartIndex = startIndex,
UserId = userId ?? Guid.Empty, UserId = userId.Value,
EnableTotalRecordCount = enableTotalRecordCount, EnableTotalRecordCount = enableTotalRecordCount,
DisableFirstEpisode = disableFirstEpisode, DisableFirstEpisode = disableFirstEpisode,
NextUpDateCutoff = nextUpDateCutoff ?? DateTime.MinValue, NextUpDateCutoff = nextUpDateCutoff ?? DateTime.MinValue,
@ -106,7 +108,7 @@ public class TvShowsController : BaseJellyfinApiController
}, },
options); options);
var user = userId is null || userId.Value.Equals(default) var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -144,7 +146,8 @@ public class TvShowsController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
[FromQuery] bool? enableUserData) [FromQuery] bool? enableUserData)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -215,7 +218,8 @@ public class TvShowsController : BaseJellyfinApiController
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] string? sortBy) [FromQuery] string? sortBy)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
@ -331,7 +335,8 @@ public class TvShowsController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
[FromQuery] bool? enableUserData) [FromQuery] bool? enableUserData)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);

View File

@ -106,11 +106,7 @@ public class UniversalAudioController : BaseJellyfinApiController
[FromQuery] bool enableRedirection = true) [FromQuery] bool enableRedirection = true)
{ {
var deviceProfile = GetDeviceProfile(container, transcodingContainer, audioCodec, transcodingProtocol, breakOnNonKeyFrames, transcodingAudioChannels, maxAudioSampleRate, maxAudioBitDepth, maxAudioChannels); var deviceProfile = GetDeviceProfile(container, transcodingContainer, audioCodec, transcodingProtocol, breakOnNonKeyFrames, transcodingAudioChannels, maxAudioSampleRate, maxAudioBitDepth, maxAudioChannels);
userId = RequestHelpers.GetUserId(User, userId);
if (!userId.HasValue || userId.Value.Equals(default))
{
userId = User.GetUserId();
}
_logger.LogInformation("GetPostedPlaybackInfo profile: {@Profile}", deviceProfile); _logger.LogInformation("GetPostedPlaybackInfo profile: {@Profile}", deviceProfile);

View File

@ -104,12 +104,13 @@ public class VideosController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId) public ActionResult<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId)
{ {
var user = userId is null || userId.Value.Equals(default) userId = RequestHelpers.GetUserId(User, userId);
var user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
var item = itemId.Equals(default) var item = itemId.Equals(default)
? (userId is null || userId.Value.Equals(default) ? (userId.Value.Equals(default)
? _libraryManager.RootFolder ? _libraryManager.RootFolder
: _libraryManager.GetUserRootFolder()) : _libraryManager.GetUserRootFolder())
: _libraryManager.GetItemById(itemId); : _libraryManager.GetItemById(itemId);

View File

@ -85,11 +85,12 @@ public class YearsController : BaseJellyfinApiController
[FromQuery] bool recursive = true, [FromQuery] bool recursive = true,
[FromQuery] bool? enableImages = true) [FromQuery] bool? enableImages = true)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields } var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User) .AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
User? user = userId is null || userId.Value.Equals(default) User? user = userId.Value.Equals(default)
? null ? null
: _userManager.GetUserById(userId.Value); : _userManager.GetUserById(userId.Value);
BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId); BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);
@ -171,6 +172,7 @@ public class YearsController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<BaseItemDto> GetYear([FromRoute, Required] int year, [FromQuery] Guid? userId) public ActionResult<BaseItemDto> GetYear([FromRoute, Required] int year, [FromQuery] Guid? userId)
{ {
userId = RequestHelpers.GetUserId(User, userId);
var item = _libraryManager.GetYear(year); var item = _libraryManager.GetYear(year);
if (item is null) if (item is null)
{ {
@ -180,7 +182,7 @@ public class YearsController : BaseJellyfinApiController
var dtoOptions = new DtoOptions() var dtoOptions = new DtoOptions()
.AddClientFields(User); .AddClientFields(User);
if (userId.HasValue && !userId.Value.Equals(default)) if (!userId.Value.Equals(default))
{ {
var user = _userManager.GetUserById(userId.Value); var user = _userManager.GetUserById(userId.Value);
return _dtoService.GetBaseItemDto(item, dtoOptions, user); return _dtoService.GetBaseItemDto(item, dtoOptions, user);

View File

@ -11,6 +11,7 @@ using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
@ -55,6 +56,32 @@ public static class RequestHelpers
return result; return result;
} }
/// <summary>
/// Checks if the user can access a user.
/// </summary>
/// <param name="claimsPrincipal">The <see cref="ClaimsPrincipal"/> for the current request.</param>
/// <param name="userId">The user id.</param>
/// <returns>A <see cref="bool"/> whether the user can access the user.</returns>
internal static Guid GetUserId(ClaimsPrincipal claimsPrincipal, Guid? userId)
{
var authenticatedUserId = claimsPrincipal.GetUserId();
// UserId not provided, fall back to authenticated user id.
if (userId is null || userId.Value.Equals(default))
{
return authenticatedUserId;
}
// User must be administrator to access another user.
var isAdministrator = claimsPrincipal.IsInRole(UserRoles.Administrator);
if (!userId.Value.Equals(authenticatedUserId) && !isAdministrator)
{
throw new SecurityException("Forbidden");
}
return userId.Value;
}
/// <summary> /// <summary>
/// Checks if the user can update an entry. /// Checks if the user can update an entry.
/// </summary> /// </summary>

View File

@ -1,7 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Security.Claims;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Net;
using Xunit; using Xunit;
namespace Jellyfin.Api.Tests.Helpers namespace Jellyfin.Api.Tests.Helpers
@ -15,6 +19,82 @@ namespace Jellyfin.Api.Tests.Helpers
Assert.Equal(expected, RequestHelpers.GetOrderBy(sortBy, requestedSortOrder)); Assert.Equal(expected, RequestHelpers.GetOrderBy(sortBy, requestedSortOrder));
} }
[Fact]
public static void GetUserId_IsAdmin()
{
Guid? requestUserId = Guid.NewGuid();
Guid? authUserId = Guid.NewGuid();
var claims = new[]
{
new Claim(InternalClaimTypes.UserId, authUserId.Value.ToString("N", CultureInfo.InvariantCulture)),
new Claim(InternalClaimTypes.IsApiKey, bool.FalseString),
new Claim(ClaimTypes.Role, UserRoles.Administrator)
};
var identity = new ClaimsIdentity(claims, string.Empty);
var principal = new ClaimsPrincipal(identity);
var userId = RequestHelpers.GetUserId(principal, requestUserId);
Assert.Equal(requestUserId, userId);
}
[Fact]
public static void GetUserId_IsApiKey_EmptyGuid()
{
Guid? requestUserId = Guid.Empty;
var claims = new[]
{
new Claim(InternalClaimTypes.IsApiKey, bool.TrueString)
};
var identity = new ClaimsIdentity(claims, string.Empty);
var principal = new ClaimsPrincipal(identity);
var userId = RequestHelpers.GetUserId(principal, requestUserId);
Assert.Equal(Guid.Empty, userId);
}
[Fact]
public static void GetUserId_IsApiKey_Null()
{
Guid? requestUserId = null;
var claims = new[]
{
new Claim(InternalClaimTypes.IsApiKey, bool.TrueString)
};
var identity = new ClaimsIdentity(claims, string.Empty);
var principal = new ClaimsPrincipal(identity);
var userId = RequestHelpers.GetUserId(principal, requestUserId);
Assert.Equal(Guid.Empty, userId);
}
[Fact]
public static void GetUserId_IsUser()
{
Guid? requestUserId = Guid.NewGuid();
Guid? authUserId = Guid.NewGuid();
var claims = new[]
{
new Claim(InternalClaimTypes.UserId, authUserId.Value.ToString("N", CultureInfo.InvariantCulture)),
new Claim(InternalClaimTypes.IsApiKey, bool.FalseString),
new Claim(ClaimTypes.Role, UserRoles.User)
};
var identity = new ClaimsIdentity(claims, string.Empty);
var principal = new ClaimsPrincipal(identity);
Assert.Throws<SecurityException>(() => RequestHelpers.GetUserId(principal, requestUserId));
}
public static TheoryData<IReadOnlyList<string>, IReadOnlyList<SortOrder>, (string, SortOrder)[]> GetOrderBy_Success_TestData() public static TheoryData<IReadOnlyList<string>, IReadOnlyList<SortOrder>, (string, SortOrder)[]> GetOrderBy_Success_TestData()
{ {
var data = new TheoryData<IReadOnlyList<string>, IReadOnlyList<SortOrder>, (string, SortOrder)[]>(); var data = new TheoryData<IReadOnlyList<string>, IReadOnlyList<SortOrder>, (string, SortOrder)[]>();

View File

@ -22,13 +22,13 @@ public sealed class ItemsControllerTests : IClassFixture<JellyfinApplicationFact
} }
[Fact] [Fact]
public async Task GetItems_NoApiKeyOrUserId_BadRequest() public async Task GetItems_NoApiKeyOrUserId_Success()
{ {
var client = _factory.CreateClient(); var client = _factory.CreateClient();
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false));
var response = await client.GetAsync("Items").ConfigureAwait(false); var response = await client.GetAsync("Items").ConfigureAwait(false);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }
[Theory] [Theory]