revise endpoint attributes

pull/702/head
Luke Pulverenti 10 years ago
parent 15a56fa069
commit a4b75934e5

@ -84,7 +84,6 @@ namespace MediaBrowser.Api
/// Gets the session.
/// </summary>
/// <returns>SessionInfo.</returns>
/// <exception cref="System.ArgumentException">Session not found.</exception>
protected SessionInfo GetSession()
{
var session = SessionContext.GetSession(Request);

@ -9,7 +9,6 @@ using MediaBrowser.Model.Serialization;
using ServiceStack;
using ServiceStack.Text.Controller;
using ServiceStack.Web;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -33,18 +32,18 @@ namespace MediaBrowser.Api
[ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Key { get; set; }
}
/// <summary>
/// Class UpdateConfiguration
/// </summary>
[Route("/System/Configuration", "POST", Summary = "Updates application configuration")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class UpdateConfiguration : ServerConfiguration, IReturnVoid
{
}
[Route("/System/Configuration/{Key}", "POST", Summary = "Updates named configuration")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class UpdateNamedConfiguration : IReturnVoid, IRequiresRequestStream
{
[ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
@ -52,23 +51,23 @@ namespace MediaBrowser.Api
public Stream RequestStream { get; set; }
}
[Route("/System/Configuration/MetadataOptions/Default", "GET", Summary = "Gets a default MetadataOptions object")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class GetDefaultMetadataOptions : IReturn<MetadataOptions>
{
}
[Route("/System/Configuration/MetadataPlugins", "GET", Summary = "Gets all available metadata plugins")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class GetMetadataPlugins : IReturn<List<MetadataPluginSummary>>
{
}
[Route("/System/Configuration/MetadataPlugins/Autoset", "POST")]
[Authenticated]
[Authenticated(Roles = "Admin", AllowBeforeStartupWizard = true)]
public class AutoSetMetadataOptions : IReturnVoid
{
@ -149,7 +148,7 @@ namespace MediaBrowser.Api
var configurationType = _configurationManager.GetConfigurationType(key);
var configuration = _jsonSerializer.DeserializeFromStream(request.RequestStream, configurationType);
_configurationManager.SaveConfiguration(key, configuration);
}

@ -12,6 +12,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Api.Devices
{
[Route("/Devices", "GET", Summary = "Gets all devices")]
[Authenticated(Roles = "Admin")]
public class GetDevices : IReturn<List<DeviceInfo>>
{
[ApiMember(Name = "SupportsContentUploading", Description = "SupportsContentUploading", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
@ -26,6 +27,7 @@ namespace MediaBrowser.Api.Devices
}
[Route("/Devices/CameraUploads", "GET", Summary = "Gets camera upload history for a device")]
[Authenticated]
public class GetCameraUploads : IReturn<ContentUploadHistory>
{
[ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
@ -33,6 +35,7 @@ namespace MediaBrowser.Api.Devices
}
[Route("/Devices/CameraUploads", "POST", Summary = "Uploads content")]
[Authenticated]
public class PostCameraUpload : IRequiresRequestStream, IReturnVoid
{
[ApiMember(Name = "DeviceId", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
@ -51,6 +54,7 @@ namespace MediaBrowser.Api.Devices
}
[Route("/Devices/Info", "GET", Summary = "Gets device info")]
[Authenticated]
public class GetDeviceInfo : IReturn<DeviceInfo>
{
[ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
@ -58,6 +62,7 @@ namespace MediaBrowser.Api.Devices
}
[Route("/Devices/Capabilities", "GET", Summary = "Gets device capabilities")]
[Authenticated]
public class GetDeviceCapabilities : IReturn<ClientCapabilities>
{
[ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
@ -65,13 +70,13 @@ namespace MediaBrowser.Api.Devices
}
[Route("/Devices/Options", "POST", Summary = "Updates device options")]
[Authenticated(Roles = "Admin")]
public class PostDeviceOptions : DeviceOptions, IReturnVoid
{
[ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
public string Id { get; set; }
}
[Authenticated]
public class DeviceService : BaseApiService
{
private readonly IDeviceManager _deviceManager;

@ -24,9 +24,6 @@ namespace MediaBrowser.Api
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
public Guid UserId { get; set; }
[ApiMember(Name = "Client", Description = "Client", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
public string Client { get; set; }
}
[Route("/DisplayPreferences/{Id}", "GET", Summary = "Gets a user's display preferences for an item")]

@ -43,7 +43,7 @@ namespace MediaBrowser.Api.Dlna
{
}
[Authenticated]
[Authenticated(Roles = "Admin")]
public class DlnaService : BaseApiService
{
private readonly IDlnaManager _dlnaManager;

@ -87,7 +87,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class EnvironmentService
/// </summary>
[Authenticated]
[Authenticated(Roles = "Admin")]
public class EnvironmentService : BaseApiService
{
const char UncSeparator = '\\';

@ -2,6 +2,7 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dto;
using ServiceStack;
using System;
@ -14,8 +15,7 @@ namespace MediaBrowser.Api.Images
/// <summary>
/// Class GetGeneralImage
/// </summary>
[Route("/Images/General/{Name}/{Type}", "GET")]
[Api(Description = "Gets a general image by name")]
[Route("/Images/General/{Name}/{Type}", "GET", Summary = "Gets a general image by name")]
public class GetGeneralImage
{
/// <summary>
@ -32,8 +32,7 @@ namespace MediaBrowser.Api.Images
/// <summary>
/// Class GetRatingImage
/// </summary>
[Route("/Images/Ratings/{Theme}/{Name}", "GET")]
[Api(Description = "Gets a rating image by name")]
[Route("/Images/Ratings/{Theme}/{Name}", "GET", Summary = "Gets a rating image by name")]
public class GetRatingImage
{
/// <summary>
@ -54,8 +53,7 @@ namespace MediaBrowser.Api.Images
/// <summary>
/// Class GetMediaInfoImage
/// </summary>
[Route("/Images/MediaInfo/{Theme}/{Name}", "GET")]
[Api(Description = "Gets a media info image by name")]
[Route("/Images/MediaInfo/{Theme}/{Name}", "GET", Summary = "Gets a media info image by name")]
public class GetMediaInfoImage
{
/// <summary>
@ -73,20 +71,20 @@ namespace MediaBrowser.Api.Images
public string Theme { get; set; }
}
[Route("/Images/MediaInfo", "GET")]
[Api(Description = "Gets all media info image by name")]
[Route("/Images/MediaInfo", "GET", Summary = "Gets all media info image by name")]
[Authenticated]
public class GetMediaInfoImages : IReturn<List<ImageByNameInfo>>
{
}
[Route("/Images/Ratings", "GET")]
[Api(Description = "Gets all rating images by name")]
[Route("/Images/Ratings", "GET", Summary = "Gets all rating images by name")]
[Authenticated]
public class GetRatingImages : IReturn<List<ImageByNameInfo>>
{
}
[Route("/Images/General", "GET")]
[Api(Description = "Gets all general images by name")]
[Route("/Images/General", "GET", Summary = "Gets all general images by name")]
[Authenticated]
public class GetGeneralImages : IReturn<List<ImageByNameInfo>>
{
}

@ -24,8 +24,7 @@ namespace MediaBrowser.Api.Images
/// <summary>
/// Class GetItemImage
/// </summary>
[Route("/Items/{Id}/Images", "GET")]
[Api(Description = "Gets information about an item's images")]
[Route("/Items/{Id}/Images", "GET", Summary = "Gets information about an item's images")]
[Authenticated]
public class GetItemImageInfos : IReturn<List<ImageInfo>>
{
@ -43,7 +42,6 @@ namespace MediaBrowser.Api.Images
[Route("/Items/{Id}/Images/{Type}/{Index}", "HEAD")]
[Route("/Items/{Id}/Images/{Type}/{Index}/{Tag}/{Format}/{MaxWidth}/{MaxHeight}/{PercentPlayed}", "GET")]
[Route("/Items/{Id}/Images/{Type}/{Index}/{Tag}/{Format}/{MaxWidth}/{MaxHeight}/{PercentPlayed}", "HEAD")]
[Api(Description = "Gets an item image")]
public class GetItemImage : ImageRequest
{
/// <summary>
@ -57,8 +55,7 @@ namespace MediaBrowser.Api.Images
/// <summary>
/// Class UpdateItemImageIndex
/// </summary>
[Route("/Items/{Id}/Images/{Type}/{Index}/Index", "POST")]
[Api(Description = "Updates the index for an item image")]
[Route("/Items/{Id}/Images/{Type}/{Index}/Index", "POST", Summary = "Updates the index for an item image")]
[Authenticated]
public class UpdateItemImageIndex : IReturnVoid
{
@ -122,7 +119,6 @@ namespace MediaBrowser.Api.Images
[Route("/Studios/{Name}/Images/{Type}/{Index}", "HEAD")]
[Route("/Years/{Year}/Images/{Type}", "HEAD")]
[Route("/Years/{Year}/Images/{Type}/{Index}", "HEAD")]
[Api(Description = "Gets an item by name image")]
public class GetItemByNameImage : ImageRequest
{
/// <summary>
@ -140,7 +136,6 @@ namespace MediaBrowser.Api.Images
[Route("/Users/{Id}/Images/{Type}/{Index}", "GET")]
[Route("/Users/{Id}/Images/{Type}", "HEAD")]
[Route("/Users/{Id}/Images/{Type}/{Index}", "HEAD")]
[Api(Description = "Gets a user image")]
public class GetUserImage : ImageRequest
{
/// <summary>
@ -156,7 +151,6 @@ namespace MediaBrowser.Api.Images
/// </summary>
[Route("/Items/{Id}/Images/{Type}", "DELETE")]
[Route("/Items/{Id}/Images/{Type}/{Index}", "DELETE")]
[Api(Description = "Deletes an item image")]
[Authenticated]
public class DeleteItemImage : DeleteImageRequest, IReturnVoid
{
@ -173,7 +167,6 @@ namespace MediaBrowser.Api.Images
/// </summary>
[Route("/Users/{Id}/Images/{Type}", "DELETE")]
[Route("/Users/{Id}/Images/{Type}/{Index}", "DELETE")]
[Api(Description = "Deletes a user image")]
[Authenticated]
public class DeleteUserImage : DeleteImageRequest, IReturnVoid
{
@ -190,7 +183,6 @@ namespace MediaBrowser.Api.Images
/// </summary>
[Route("/Users/{Id}/Images/{Type}", "POST")]
[Route("/Users/{Id}/Images/{Type}/{Index}", "POST")]
[Api(Description = "Posts a user image")]
[Authenticated]
public class PostUserImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid
{

@ -5,11 +5,11 @@ using MediaBrowser.Controller;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using ServiceStack;
using ServiceStack.Text.Controller;
using System;
using System.Collections.Generic;
using System.IO;
@ -45,8 +45,8 @@ namespace MediaBrowser.Api.Images
public bool IncludeAllLanguages { get; set; }
}
[Route("/Items/{Id}/RemoteImages", "GET")]
[Api(Description = "Gets available remote images for an item")]
[Route("/Items/{Id}/RemoteImages", "GET", Summary = "Gets available remote images for an item")]
[Authenticated]
public class GetRemoteImages : BaseRemoteImageRequest
{
/// <summary>
@ -57,25 +57,8 @@ namespace MediaBrowser.Api.Images
public string Id { get; set; }
}
[Route("/Artists/{Name}/RemoteImages", "GET")]
[Route("/Genres/{Name}/RemoteImages", "GET")]
[Route("/GameGenres/{Name}/RemoteImages", "GET")]
[Route("/MusicGenres/{Name}/RemoteImages", "GET")]
[Route("/Persons/{Name}/RemoteImages", "GET")]
[Route("/Studios/{Name}/RemoteImages", "GET")]
[Api(Description = "Gets available remote images for an item")]
public class GetItemByNameRemoteImages : BaseRemoteImageRequest
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Name { get; set; }
}
[Route("/Items/{Id}/RemoteImages/Providers", "GET")]
[Api(Description = "Gets available remote image providers for an item")]
[Route("/Items/{Id}/RemoteImages/Providers", "GET", Summary = "Gets available remote image providers for an item")]
[Authenticated]
public class GetRemoteImageProviders : IReturn<List<ImageProviderInfo>>
{
/// <summary>
@ -86,23 +69,6 @@ namespace MediaBrowser.Api.Images
public string Id { get; set; }
}
[Route("/Artists/{Name}/RemoteImages/Providers", "GET")]
[Route("/Genres/{Name}/RemoteImages/Providers", "GET")]
[Route("/GameGenres/{Name}/RemoteImages/Providers", "GET")]
[Route("/MusicGenres/{Name}/RemoteImages/Providers", "GET")]
[Route("/Persons/{Name}/RemoteImages/Providers", "GET")]
[Route("/Studios/{Name}/RemoteImages/Providers", "GET")]
[Api(Description = "Gets available remote image providers for an item")]
public class GetItemByNameRemoteImageProviders : IReturn<List<ImageProviderInfo>>
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Name { get; set; }
}
public class BaseDownloadRemoteImage : IReturnVoid
{
[ApiMember(Name = "Type", Description = "The image type", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
@ -115,8 +81,8 @@ namespace MediaBrowser.Api.Images
public string ImageUrl { get; set; }
}
[Route("/Items/{Id}/RemoteImages/Download", "POST")]
[Api(Description = "Downloads a remote image for an item")]
[Route("/Items/{Id}/RemoteImages/Download", "POST", Summary = "Downloads a remote image for an item")]
[Authenticated(Roles="Admin")]
public class DownloadRemoteImage : BaseDownloadRemoteImage
{
/// <summary>
@ -127,25 +93,7 @@ namespace MediaBrowser.Api.Images
public string Id { get; set; }
}
[Route("/Artists/{Name}/RemoteImages/Download", "POST")]
[Route("/Genres/{Name}/RemoteImages/Download", "POST")]
[Route("/GameGenres/{Name}/RemoteImages/Download", "POST")]
[Route("/MusicGenres/{Name}/RemoteImages/Download", "POST")]
[Route("/Persons/{Name}/RemoteImages/Download", "POST")]
[Route("/Studios/{Name}/RemoteImages/Download", "POST")]
[Api(Description = "Downloads a remote image for an item")]
public class DownloadItemByNameRemoteImage : BaseDownloadRemoteImage
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string Name { get; set; }
}
[Route("/Images/Remote", "GET")]
[Api(Description = "Gets a remote image")]
[Route("/Images/Remote", "GET", Summary = "Gets a remote image")]
public class GetRemoteImage
{
[ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
@ -182,18 +130,6 @@ namespace MediaBrowser.Api.Images
return ToOptimizedSerializedResultUsingCache(result);
}
public object Get(GetItemByNameRemoteImageProviders request)
{
var pathInfo = PathInfo.Parse(Request.PathInfo);
var type = pathInfo.GetArgumentValue<string>(0);
var item = GetItemByName(request.Name, type, _libraryManager);
var result = GetImageProviders(item);
return ToOptimizedSerializedResultUsingCache(result);
}
private List<ImageProviderInfo> GetImageProviders(BaseItem item)
{
return _providerManager.GetRemoteImageProviderInfo(item).ToList();
@ -206,16 +142,6 @@ namespace MediaBrowser.Api.Images
return await GetRemoteImageResult(item, request).ConfigureAwait(false);
}
public async Task<object> Get(GetItemByNameRemoteImages request)
{
var pathInfo = PathInfo.Parse(Request.PathInfo);
var type = pathInfo.GetArgumentValue<string>(0);
var item = GetItemByName(request.Name, type, _libraryManager);
return await GetRemoteImageResult(item, request).ConfigureAwait(false);
}
private async Task<RemoteImageResult> GetRemoteImageResult(BaseItem item, BaseRemoteImageRequest request)
{
var images = await _providerManager.GetAvailableRemoteImages(item, new RemoteImageQuery
@ -274,18 +200,6 @@ namespace MediaBrowser.Api.Images
Task.WaitAll(task);
}
public void Post(DownloadItemByNameRemoteImage request)
{
var pathInfo = PathInfo.Parse(Request.PathInfo);
var type = pathInfo.GetArgumentValue<string>(0);
var item = GetItemByName(request.Name, type, _libraryManager);
var task = DownloadRemoteImage(item, request);
Task.WaitAll(task);
}
/// <summary>
/// Downloads the remote image.
/// </summary>

@ -8,7 +8,6 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using ServiceStack;
using System;
@ -20,9 +19,8 @@ using System.Threading.Tasks;
namespace MediaBrowser.Api
{
[Route("/Items/{Id}/ExternalIdInfos", "GET")]
[Api(Description = "Gets external id infos for an item")]
[Authenticated]
[Route("/Items/{Id}/ExternalIdInfos", "GET", Summary = "Gets external id infos for an item")]
[Authenticated(Roles = "Admin")]
public class GetExternalIdInfos : IReturn<List<ExternalIdInfo>>
{
/// <summary>
@ -34,70 +32,60 @@ namespace MediaBrowser.Api
}
[Route("/Items/RemoteSearch/Movie", "POST")]
[Api(Description = "Gets external id infos for an item")]
[Authenticated]
public class GetMovieRemoteSearchResults : RemoteSearchQuery<MovieInfo>, IReturn<List<RemoteSearchResult>>
{
}
[Route("/Items/RemoteSearch/Trailer", "POST")]
[Api(Description = "Gets external id infos for an item")]
[Authenticated]
public class GetTrailerRemoteSearchResults : RemoteSearchQuery<TrailerInfo>, IReturn<List<RemoteSearchResult>>
{
}
[Route("/Items/RemoteSearch/AdultVideo", "POST")]
[Api(Description = "Gets external id infos for an item")]
[Authenticated]
public class GetAdultVideoRemoteSearchResults : RemoteSearchQuery<ItemLookupInfo>, IReturn<List<RemoteSearchResult>>
{
}
[Route("/Items/RemoteSearch/Series", "POST")]
[Api(Description = "Gets external id infos for an item")]
[Authenticated]
public class GetSeriesRemoteSearchResults : RemoteSearchQuery<SeriesInfo>, IReturn<List<RemoteSearchResult>>
{
}
[Route("/Items/RemoteSearch/Game", "POST")]
[Api(Description = "Gets external id infos for an item")]
[Authenticated]
public class GetGameRemoteSearchResults : RemoteSearchQuery<GameInfo>, IReturn<List<RemoteSearchResult>>
{
}
[Route("/Items/RemoteSearch/BoxSet", "POST")]
[Api(Description = "Gets external id infos for an item")]
[Authenticated]
public class GetBoxSetRemoteSearchResults : RemoteSearchQuery<BoxSetInfo>, IReturn<List<RemoteSearchResult>>
{
}
[Route("/Items/RemoteSearch/MusicArtist", "POST")]
[Api(Description = "Gets external id infos for an item")]
[Authenticated]
public class GetMusicArtistRemoteSearchResults : RemoteSearchQuery<ArtistInfo>, IReturn<List<RemoteSearchResult>>
{
}
[Route("/Items/RemoteSearch/MusicAlbum", "POST")]
[Api(Description = "Gets external id infos for an item")]
[Authenticated]
public class GetMusicAlbumRemoteSearchResults : RemoteSearchQuery<AlbumInfo>, IReturn<List<RemoteSearchResult>>
{
}
[Route("/Items/RemoteSearch/Person", "POST")]
[Api(Description = "Gets external id infos for an item")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class GetPersonRemoteSearchResults : RemoteSearchQuery<PersonLookupInfo>, IReturn<List<RemoteSearchResult>>
{
}
[Route("/Items/RemoteSearch/Image", "GET")]
[Api(Description = "Gets a remote image")]
[Route("/Items/RemoteSearch/Image", "GET", Summary = "Gets a remote image")]
public class GetRemoteSearchImage
{
[ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
@ -107,9 +95,8 @@ namespace MediaBrowser.Api
public string ProviderName { get; set; }
}
[Route("/Items/RemoteSearch/Apply/{Id}", "POST")]
[Api(Description = "Applies search criteria to an item and refreshes metadata")]
[Authenticated]
[Route("/Items/RemoteSearch/Apply/{Id}", "POST", Summary = "Applies search criteria to an item and refreshes metadata")]
[Authenticated(Roles = "Admin")]
public class ApplySearchCriteria : RemoteSearchResult, IReturnVoid
{
[ApiMember(Name = "Id", Description = "The item id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]

@ -26,8 +26,7 @@ namespace MediaBrowser.Api
public bool ReplaceAllImages { get; set; }
}
[Route("/Items/{Id}/Refresh", "POST")]
[Api(Description = "Refreshes metadata for an item")]
[Route("/Items/{Id}/Refresh", "POST", Summary = "Refreshes metadata for an item")]
public class RefreshItem : BaseRefreshRequest
{
[ApiMember(Name = "Recursive", Description = "Indicates if the refresh should occur recursively.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]

@ -7,8 +7,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Api.Library
{
[Route("/Library/FileOrganization", "GET")]
[Api(Description = "Gets file organization results")]
[Route("/Library/FileOrganization", "GET", Summary = "Gets file organization results")]
public class GetFileOrganizationActivity : IReturn<QueryResult<FileOrganizationResult>>
{
/// <summary>
@ -26,14 +25,12 @@ namespace MediaBrowser.Api.Library
public int? Limit { get; set; }
}
[Route("/Library/FileOrganizations", "DELETE")]
[Api(Description = "Clears the activity log")]
[Route("/Library/FileOrganizations", "DELETE", Summary = "Clears the activity log")]
public class ClearOrganizationLog : IReturnVoid
{
}
[Route("/Library/FileOrganizations/{Id}/File", "DELETE")]
[Api(Description = "Deletes the original file of a organizer result")]
[Route("/Library/FileOrganizations/{Id}/File", "DELETE", Summary = "Deletes the original file of a organizer result")]
public class DeleteOriginalFile : IReturnVoid
{
/// <summary>
@ -44,8 +41,7 @@ namespace MediaBrowser.Api.Library
public string Id { get; set; }
}
[Route("/Library/FileOrganizations/{Id}/Organize", "POST")]
[Api(Description = "Performs an organization")]
[Route("/Library/FileOrganizations/{Id}/Organize", "POST", Summary = "Performs an organization")]
public class PerformOrganization : IReturn<QueryResult<FileOrganizationResult>>
{
/// <summary>
@ -56,8 +52,7 @@ namespace MediaBrowser.Api.Library
public string Id { get; set; }
}
[Route("/Library/FileOrganizations/{Id}/Episode/Organize", "POST")]
[Api(Description = "Performs an organization")]
[Route("/Library/FileOrganizations/{Id}/Episode/Organize", "POST", Summary = "Performs an organization")]
public class OrganizeEpisode
{
[ApiMember(Name = "Id", Description = "Result Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
@ -79,7 +74,7 @@ namespace MediaBrowser.Api.Library
public bool RememberCorrection { get; set; }
}
[Authenticated]
[Authenticated(Roles = "Admin")]
public class FileOrganizationService : BaseApiService
{
private readonly IFileOrganizationService _iFileOrganizationService;

@ -23,8 +23,8 @@ using System.Threading.Tasks;
namespace MediaBrowser.Api.Library
{
[Route("/Items/{Id}/File", "GET")]
[Api(Description = "Gets the original file of an item")]
[Route("/Items/{Id}/File", "GET", Summary = "Gets the original file of an item")]
[Authenticated]
public class GetFile
{
/// <summary>
@ -38,8 +38,8 @@ namespace MediaBrowser.Api.Library
/// <summary>
/// Class GetCriticReviews
/// </summary>
[Route("/Items/{Id}/CriticReviews", "GET")]
[Api(Description = "Gets critic reviews for an item")]
[Route("/Items/{Id}/CriticReviews", "GET", Summary = "Gets critic reviews for an item")]
[Authenticated]
public class GetCriticReviews : IReturn<QueryResult<ItemReview>>
{
/// <summary>
@ -67,8 +67,8 @@ namespace MediaBrowser.Api.Library
/// <summary>
/// Class GetThemeSongs
/// </summary>
[Route("/Items/{Id}/ThemeSongs", "GET")]
[Api(Description = "Gets theme songs for an item")]
[Route("/Items/{Id}/ThemeSongs", "GET", Summary = "Gets theme songs for an item")]
[Authenticated]
public class GetThemeSongs : IReturn<ThemeMediaResult>
{
/// <summary>
@ -92,8 +92,8 @@ namespace MediaBrowser.Api.Library
/// <summary>
/// Class GetThemeVideos
/// </summary>
[Route("/Items/{Id}/ThemeVideos", "GET")]
[Api(Description = "Gets theme videos for an item")]
[Route("/Items/{Id}/ThemeVideos", "GET", Summary = "Gets theme videos for an item")]
[Authenticated]
public class GetThemeVideos : IReturn<ThemeMediaResult>
{
/// <summary>
@ -117,8 +117,8 @@ namespace MediaBrowser.Api.Library
/// <summary>
/// Class GetThemeVideos
/// </summary>
[Route("/Items/{Id}/ThemeMedia", "GET")]
[Api(Description = "Gets theme videos and songs for an item")]
[Route("/Items/{Id}/ThemeMedia", "GET", Summary = "Gets theme videos and songs for an item")]
[Authenticated]
public class GetThemeMedia : IReturn<AllThemeMediaResult>
{
/// <summary>
@ -139,14 +139,14 @@ namespace MediaBrowser.Api.Library
public bool InheritFromParent { get; set; }
}
[Route("/Library/Refresh", "POST")]
[Api(Description = "Starts a library scan")]
[Route("/Library/Refresh", "POST", Summary = "Starts a library scan")]
[Authenticated(Roles = "Admin")]
public class RefreshLibrary : IReturnVoid
{
}
[Route("/Items/{Id}", "DELETE")]
[Api(Description = "Deletes an item from the library and file system")]
[Route("/Items/{Id}", "DELETE", Summary = "Deletes an item from the library and file system")]
[Authenticated(Roles = "Delete")]
public class DeleteItem : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
@ -154,7 +154,7 @@ namespace MediaBrowser.Api.Library
}
[Route("/Items/Counts", "GET")]
[Api(Description = "Gets counts of various item types")]
[Authenticated]
public class GetItemCounts : IReturn<ItemCounts>
{
[ApiMember(Name = "UserId", Description = "Optional. Get counts from a specific user's library.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
@ -164,8 +164,8 @@ namespace MediaBrowser.Api.Library
public bool? IsFavorite { get; set; }
}
[Route("/Items/{Id}/Ancestors", "GET")]
[Api(Description = "Gets all parents of an item")]
[Route("/Items/{Id}/Ancestors", "GET", Summary = "Gets all parents of an item")]
[Authenticated]
public class GetAncestors : IReturn<BaseItemDto[]>
{
/// <summary>
@ -183,8 +183,8 @@ namespace MediaBrowser.Api.Library
public string Id { get; set; }
}
[Route("/Items/YearIndex", "GET")]
[Api(Description = "Gets a year index based on an item query.")]
[Route("/Items/YearIndex", "GET", Summary = "Gets a year index based on an item query.")]
[Authenticated]
public class GetYearIndex : IReturn<List<ItemIndex>>
{
/// <summary>
@ -201,23 +201,23 @@ namespace MediaBrowser.Api.Library
/// <summary>
/// Class GetPhyscialPaths
/// </summary>
[Route("/Library/PhysicalPaths", "GET")]
[Api(Description = "Gets a list of physical paths from virtual folders")]
[Route("/Library/PhysicalPaths", "GET", Summary = "Gets a list of physical paths from virtual folders")]
[Authenticated(Roles = "Admin")]
public class GetPhyscialPaths : IReturn<List<string>>
{
}
[Route("/Library/MediaFolders", "GET")]
[Api(Description = "Gets all user media folders.")]
[Route("/Library/MediaFolders", "GET", Summary = "Gets all user media folders.")]
[Authenticated]
public class GetMediaFolders : IReturn<ItemsResult>
{
[ApiMember(Name = "IsHidden", Description = "Optional. Filter by folders that are marked hidden, or not.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? IsHidden { get; set; }
}
[Route("/Library/Series/Added", "POST")]
[Route("/Library/Series/Updated", "POST")]
[Api(Description = "Reports that new episodes of a series have been added by an external source")]
[Route("/Library/Series/Added", "POST", Summary = "Reports that new episodes of a series have been added by an external source")]
[Route("/Library/Series/Updated", "POST", Summary = "Reports that new episodes of a series have been added by an external source")]
[Authenticated]
public class PostUpdatedSeries : IReturnVoid
{
[ApiMember(Name = "TvdbId", Description = "Tvdb Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
@ -227,7 +227,6 @@ namespace MediaBrowser.Api.Library
/// <summary>
/// Class LibraryService
/// </summary>
[Authenticated]
public class LibraryService : BaseApiService
{
/// <summary>

@ -131,11 +131,11 @@ namespace MediaBrowser.Api.Library
/// <value><c>true</c> if [refresh library]; otherwise, <c>false</c>.</value>
public bool RefreshLibrary { get; set; }
}
/// <summary>
/// Class LibraryStructureService
/// </summary>
[Authenticated]
[Authenticated(Roles = "Admin", AllowBeforeStartupWizard = true)]
public class LibraryStructureService : BaseApiService
{
/// <summary>
@ -164,7 +164,6 @@ namespace MediaBrowser.Api.Library
/// <param name="appPaths">The app paths.</param>
/// <param name="userManager">The user manager.</param>
/// <param name="libraryManager">The library manager.</param>
/// <exception cref="System.ArgumentNullException">appPaths</exception>
public LibraryStructureService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, ILogger logger)
{
if (appPaths == null)

@ -18,6 +18,7 @@ namespace MediaBrowser.Api.LiveTv
/// This is insecure right now to avoid windows phone refactoring
/// </summary>
[Route("/LiveTv/Info", "GET", Summary = "Gets available live tv services.")]
[Authenticated]
public class GetLiveTvInfo : IReturn<LiveTvInfo>
{
}

@ -43,7 +43,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class CulturesService
/// </summary>
[Authenticated]
[Authenticated(AllowBeforeStartupWizard = true)]
public class LocalizationService : BaseApiService
{
/// <summary>

@ -69,6 +69,7 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="AppThemeService.cs" />
<Compile Include="BrandingService.cs" />
<Compile Include="ChannelService.cs" />
<Compile Include="ConnectService.cs" />
@ -79,10 +80,10 @@
<Compile Include="Library\ChapterService.cs" />
<Compile Include="Playback\Hls\MpegDashService.cs" />
<Compile Include="PlaylistService.cs" />
<Compile Include="StartupWizardService.cs" />
<Compile Include="Subtitles\SubtitleService.cs" />
<Compile Include="Movies\CollectionService.cs" />
<Compile Include="Music\AlbumsService.cs" />
<Compile Include="AppThemeService.cs" />
<Compile Include="BaseApiService.cs" />
<Compile Include="ConfigurationService.cs" />
<Compile Include="DisplayPreferencesService.cs" />

@ -122,7 +122,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class PackageService
/// </summary>
[Authenticated]
[Authenticated(Roles = "Admin")]
public class PackageService : BaseApiService
{
private readonly IInstallationManager _installationManager;

@ -6,7 +6,6 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Playlists;
using MediaBrowser.Model.Querying;
using ServiceStack;
using System;
using System.Linq;
using System.Threading.Tasks;

@ -20,6 +20,7 @@ namespace MediaBrowser.Api
/// Class Plugins
/// </summary>
[Route("/Plugins", "GET", Summary = "Gets a list of currently installed plugins")]
[Authenticated]
public class GetPlugins : IReturn<List<PluginInfo>>
{
}
@ -28,6 +29,7 @@ namespace MediaBrowser.Api
/// Class UninstallPlugin
/// </summary>
[Route("/Plugins/{Id}", "DELETE", Summary = "Uninstalls a plugin")]
[Authenticated(Roles = "Admin")]
public class UninstallPlugin : IReturnVoid
{
/// <summary>
@ -42,6 +44,7 @@ namespace MediaBrowser.Api
/// Class GetPluginConfiguration
/// </summary>
[Route("/Plugins/{Id}/Configuration", "GET", Summary = "Gets a plugin's configuration")]
[Authenticated]
public class GetPluginConfiguration
{
/// <summary>
@ -56,6 +59,7 @@ namespace MediaBrowser.Api
/// Class UpdatePluginConfiguration
/// </summary>
[Route("/Plugins/{Id}/Configuration", "POST", Summary = "Updates a plugin's configuration")]
[Authenticated]
public class UpdatePluginConfiguration : IRequiresRequestStream, IReturnVoid
{
/// <summary>
@ -76,6 +80,7 @@ namespace MediaBrowser.Api
/// Class GetPluginSecurityInfo
/// </summary>
[Route("/Plugins/SecurityInfo", "GET", Summary = "Gets plugin registration information")]
[Authenticated]
public class GetPluginSecurityInfo : IReturn<PluginSecurityInfo>
{
}
@ -84,11 +89,13 @@ namespace MediaBrowser.Api
/// Class UpdatePluginSecurityInfo
/// </summary>
[Route("/Plugins/SecurityInfo", "POST", Summary = "Updates plugin registration information")]
[Authenticated(Roles = "Admin")]
public class UpdatePluginSecurityInfo : PluginSecurityInfo, IReturnVoid
{
}
[Route("/Plugins/RegistrationRecords/{Name}", "GET", Summary = "Gets registration status for a feature")]
[Authenticated]
public class GetRegistrationStatus
{
[ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
@ -97,11 +104,10 @@ namespace MediaBrowser.Api
[ApiMember(Name = "Mb2Equivalent", Description = "Optional. The equivalent feature name in MB2", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Mb2Equivalent { get; set; }
}
/// <summary>
/// Class PluginsService
/// </summary>
[Authenticated]
public class PluginService : BaseApiService
{
/// <summary>
@ -118,14 +124,6 @@ namespace MediaBrowser.Api
private readonly IInstallationManager _installationManager;
/// <summary>
/// Initializes a new instance of the <see cref="PluginService" /> class.
/// </summary>
/// <param name="jsonSerializer">The json serializer.</param>
/// <param name="appHost">The app host.</param>
/// <param name="securityManager">The security manager.</param>
/// <param name="installationManager">The installation manager.</param>
/// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
public PluginService(IJsonSerializer jsonSerializer, IApplicationHost appHost, ISecurityManager securityManager, IInstallationManager installationManager)
: base()
{
@ -151,7 +149,7 @@ namespace MediaBrowser.Api
return ToOptimizedResult(result);
}
/// <summary>
/// Gets the specified request.
/// </summary>

@ -79,7 +79,7 @@ namespace MediaBrowser.Api.ScheduledTasks
/// <summary>
/// Class ScheduledTasksService
/// </summary>
[Authenticated]
[Authenticated(Roles = "Admin")]
public class ScheduledTaskService : BaseApiService
{
/// <summary>

@ -241,16 +241,19 @@ namespace MediaBrowser.Api.Session
}
[Route("/Sessions/Logout", "POST", Summary = "Reports that a session has ended")]
[Authenticated]
public class ReportSessionEnded : IReturnVoid
{
}
[Route("/Auth/Keys", "GET")]
[Authenticated(Roles = "Admin")]
public class GetApiKeys
{
}
[Route("/Auth/Keys/{Key}", "DELETE")]
[Authenticated(Roles = "Admin")]
public class RevokeKey
{
[ApiMember(Name = "Key", Description = "Auth Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
@ -258,6 +261,7 @@ namespace MediaBrowser.Api.Session
}
[Route("/Auth/Keys", "POST")]
[Authenticated(Roles = "Admin")]
public class CreateKey
{
[ApiMember(Name = "App", Description = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]

@ -0,0 +1,163 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Connect;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Configuration;
using ServiceStack;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace MediaBrowser.Api
{
[Route("/Startup/Complete", "POST", Summary = "Reports that the startup wizard has been completed")]
public class ReportStartupWizardComplete : IReturnVoid
{
}
[Route("/Startup/Info", "GET", Summary = "Gets initial server info")]
public class GetStartupInfo : IReturn<StartupInfo>
{
}
[Route("/Startup/Configuration", "GET", Summary = "Gets initial server configuration")]
public class GetStartupConfiguration : IReturn<StartupConfiguration>
{
}
[Route("/Startup/Configuration", "POST", Summary = "Updates initial server configuration")]
public class UpdateStartupConfiguration : StartupConfiguration, IReturnVoid
{
}
[Route("/Startup/User", "GET", Summary = "Gets initial user info")]
public class GetStartupUser : IReturn<StartupUser>
{
}
[Route("/Startup/User", "POST", Summary = "Updates initial user info")]
public class UpdateStartupUser : StartupUser, IReturn<UpdateStartupUserResult>
{
}
[Authenticated(AllowBeforeStartupWizard = true, Roles = "Admin")]
public class StartupWizardService : BaseApiService
{
private readonly IServerConfigurationManager _config;
private readonly IServerApplicationHost _appHost;
private readonly IUserManager _userManager;
private readonly IConnectManager _connectManager;
public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager)
{
_config = config;
_appHost = appHost;
_userManager = userManager;
_connectManager = connectManager;
}
public void Post(ReportStartupWizardComplete request)
{
_config.Configuration.IsStartupWizardCompleted = true;
_config.SaveConfiguration();
}
public object Get(GetStartupInfo request)
{
var info = _appHost.GetSystemInfo();
return new StartupInfo
{
SupportsRunningAsService = info.SupportsRunningAsService
};
}
public object Get(GetStartupConfiguration request)
{
return new StartupConfiguration
{
UICulture = _config.Configuration.UICulture,
EnableInternetProviders = _config.Configuration.EnableInternetProviders,
SaveLocalMeta = _config.Configuration.SaveLocalMeta,
MetadataCountryCode = _config.Configuration.MetadataCountryCode,
PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage
};
}
public void Post(UpdateStartupConfiguration request)
{
_config.Configuration.UICulture = request.UICulture;
_config.Configuration.EnableInternetProviders = request.EnableInternetProviders;
_config.Configuration.SaveLocalMeta = request.SaveLocalMeta;
_config.Configuration.MetadataCountryCode = request.MetadataCountryCode;
_config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
_config.SaveConfiguration();
}
public object Get(GetStartupUser request)
{
var user = _userManager.Users.First();
return new StartupUser
{
Name = user.Name,
ConnectUserName = user.ConnectUserName
};
}
public async Task<object> Post(UpdateStartupUser request)
{
var user = _userManager.Users.First();
// TODO: This should be handled internally by xbmc metadata
const string metadataKey = "xbmcmetadata";
var metadata = _config.GetConfiguration<XbmcMetadataOptions>(metadataKey);
metadata.UserId = user.Id.ToString("N");
_config.SaveConfiguration(metadataKey, metadata);
user.Name = request.Name;
await _userManager.UpdateUser(user).ConfigureAwait(false);
var result = new UpdateStartupUserResult();
if (!string.IsNullOrWhiteSpace(user.ConnectUserName) &&
string.IsNullOrWhiteSpace(request.ConnectUserName))
{
await _connectManager.RemoveConnect(user.Id.ToString("N")).ConfigureAwait(false);
}
else if (!string.Equals(user.ConnectUserName, request.ConnectUserName, StringComparison.OrdinalIgnoreCase))
{
result.UserLinkResult = await _connectManager.LinkUser(user.Id.ToString("N"), request.ConnectUserName).ConfigureAwait(false);
}
return result;
}
}
public class StartupConfiguration
{
public string UICulture { get; set; }
public bool EnableInternetProviders { get; set; }
public bool SaveLocalMeta { get; set; }
public string MetadataCountryCode { get; set; }
public string PreferredMetadataLanguage { get; set; }
}
public class StartupInfo
{
public bool SupportsRunningAsService { get; set; }
}
public class StartupUser
{
public string Name { get; set; }
public string ConnectUserName { get; set; }
}
public class UpdateStartupUserResult
{
public UserLinkResult UserLinkResult { get; set; }
}
}

@ -19,7 +19,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Api.Subtitles
{
[Route("/Videos/{Id}/Subtitles/{Index}", "DELETE", Summary = "Deletes an external subtitle file")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class DeleteSubtitle
{
/// <summary>

@ -29,7 +29,7 @@ namespace MediaBrowser.Api.System
public string MinDate { get; set; }
}
[Authenticated]
[Authenticated(Roles = "Admin")]
public class ActivityLogService : BaseApiService
{
private readonly IActivityManager _activityManager;

@ -35,7 +35,7 @@ namespace MediaBrowser.Api.System
/// Class RestartApplication
/// </summary>
[Route("/System/Restart", "POST", Summary = "Restarts the application, if needed")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class RestartApplication
{
}
@ -51,7 +51,7 @@ namespace MediaBrowser.Api.System
}
[Route("/System/Logs", "GET", Summary = "Gets a list of available server log files")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class GetServerLogs : IReturn<List<LogFile>>
{
}
@ -64,6 +64,7 @@ namespace MediaBrowser.Api.System
}
[Route("/System/Logs/Log", "GET", Summary = "Gets a log file")]
[Authenticated(Roles = "Admin")]
public class GetLogFile
{
[ApiMember(Name = "Name", Description = "The log file name.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]

@ -1,5 +1,4 @@
using MediaBrowser.Api.UserLibrary;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;

@ -13,8 +13,7 @@ using System.Linq;
namespace MediaBrowser.Api.UserLibrary
{
[Route("/GameGenres", "GET")]
[Api(Description = "Gets all Game genres from a given item, folder, or the entire library")]
[Route("/GameGenres", "GET", Summary = "Gets all Game genres from a given item, folder, or the entire library")]
public class GetGameGenres : GetItemsByName
{
public GetGameGenres()
@ -23,8 +22,7 @@ namespace MediaBrowser.Api.UserLibrary
}
}
[Route("/GameGenres/{Name}", "GET")]
[Api(Description = "Gets a Game genre, by name")]
[Route("/GameGenres/{Name}", "GET", Summary = "Gets a Game genre, by name")]
public class GetGameGenre : IReturn<BaseItemDto>
{
/// <summary>

@ -16,8 +16,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetGenres
/// </summary>
[Route("/Genres", "GET")]
[Api(Description = "Gets all genres from a given item, folder, or the entire library")]
[Route("/Genres", "GET", Summary = "Gets all genres from a given item, folder, or the entire library")]
public class GetGenres : GetItemsByName
{
}
@ -25,8 +24,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetGenre
/// </summary>
[Route("/Genres/{Name}", "GET")]
[Api(Description = "Gets a genre, by name")]
[Route("/Genres/{Name}", "GET", Summary = "Gets a genre, by name")]
public class GetGenre : IReturn<BaseItemDto>
{
/// <summary>

@ -13,8 +13,7 @@ using System.Linq;
namespace MediaBrowser.Api.UserLibrary
{
[Route("/MusicGenres", "GET")]
[Api(Description = "Gets all music genres from a given item, folder, or the entire library")]
[Route("/MusicGenres", "GET", Summary = "Gets all music genres from a given item, folder, or the entire library")]
public class GetMusicGenres : GetItemsByName
{
public GetMusicGenres()
@ -23,8 +22,7 @@ namespace MediaBrowser.Api.UserLibrary
}
}
[Route("/MusicGenres/{Name}", "GET")]
[Api(Description = "Gets a music genre, by name")]
[Route("/MusicGenres/{Name}", "GET", Summary = "Gets a music genre, by name")]
public class GetMusicGenre : IReturn<BaseItemDto>
{
/// <summary>

@ -15,8 +15,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetPersons
/// </summary>
[Route("/Persons", "GET")]
[Api(Description = "Gets all persons from a given item, folder, or the entire library")]
[Route("/Persons", "GET", Summary = "Gets all persons from a given item, folder, or the entire library")]
public class GetPersons : GetItemsByName
{
/// <summary>
@ -30,8 +29,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetPerson
/// </summary>
[Route("/Persons/{Name}", "GET")]
[Api(Description = "Gets a person, by name")]
[Route("/Persons/{Name}", "GET", Summary = "Gets a person, by name")]
public class GetPerson : IReturn<BaseItemDto>
{
/// <summary>

@ -15,8 +15,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class MarkPlayedItem
/// </summary>
[Route("/Users/{UserId}/PlayedItems/{Id}", "POST")]
[Api(Description = "Marks an item as played")]
[Route("/Users/{UserId}/PlayedItems/{Id}", "POST", Summary = "Marks an item as played")]
public class MarkPlayedItem : IReturn<UserItemDataDto>
{
/// <summary>
@ -40,8 +39,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class MarkUnplayedItem
/// </summary>
[Route("/Users/{UserId}/PlayedItems/{Id}", "DELETE")]
[Api(Description = "Marks an item as unplayed")]
[Route("/Users/{UserId}/PlayedItems/{Id}", "DELETE", Summary = "Marks an item as unplayed")]
public class MarkUnplayedItem : IReturn<UserItemDataDto>
{
/// <summary>
@ -59,20 +57,17 @@ namespace MediaBrowser.Api.UserLibrary
public string Id { get; set; }
}
[Route("/Sessions/Playing", "POST")]
[Api(Description = "Reports playback has started within a session")]
[Route("/Sessions/Playing", "POST", Summary = "Reports playback has started within a session")]
public class ReportPlaybackStart : PlaybackStartInfo, IReturnVoid
{
}
[Route("/Sessions/Playing/Progress", "POST")]
[Api(Description = "Reports playback progress within a session")]
[Route("/Sessions/Playing/Progress", "POST", Summary = "Reports playback progress within a session")]
public class ReportPlaybackProgress : PlaybackProgressInfo, IReturnVoid
{
}
[Route("/Sessions/Playing/Stopped", "POST")]
[Api(Description = "Reports playback has stopped within a session")]
[Route("/Sessions/Playing/Stopped", "POST", Summary = "Reports playback has stopped within a session")]
public class ReportPlaybackStopped : PlaybackStopInfo, IReturnVoid
{
}
@ -80,8 +75,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class OnPlaybackStart
/// </summary>
[Route("/Users/{UserId}/PlayingItems/{Id}", "POST")]
[Api(Description = "Reports that a user has begun playing an item")]
[Route("/Users/{UserId}/PlayingItems/{Id}", "POST", Summary = "Reports that a user has begun playing an item")]
public class OnPlaybackStart : IReturnVoid
{
/// <summary>
@ -125,8 +119,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class OnPlaybackProgress
/// </summary>
[Route("/Users/{UserId}/PlayingItems/{Id}/Progress", "POST")]
[Api(Description = "Reports a user's playback progress")]
[Route("/Users/{UserId}/PlayingItems/{Id}/Progress", "POST", Summary = "Reports a user's playback progress")]
public class OnPlaybackProgress : IReturnVoid
{
/// <summary>
@ -172,8 +165,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class OnPlaybackStopped
/// </summary>
[Route("/Users/{UserId}/PlayingItems/{Id}", "DELETE")]
[Api(Description = "Reports that a user has stopped playing an item")]
[Route("/Users/{UserId}/PlayingItems/{Id}", "DELETE", Summary = "Reports that a user has stopped playing an item")]
public class OnPlaybackStopped : IReturnVoid
{
/// <summary>

@ -1,6 +1,5 @@
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
@ -21,8 +20,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetItem
/// </summary>
[Route("/Users/{UserId}/Items/{Id}", "GET")]
[Api(Description = "Gets an item from a user's library")]
[Route("/Users/{UserId}/Items/{Id}", "GET", Summary = "Gets an item from a user's library")]
public class GetItem : IReturn<BaseItemDto>
{
/// <summary>
@ -57,8 +55,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetItem
/// </summary>
[Route("/Users/{UserId}/Items/Root", "GET")]
[Api(Description = "Gets the root folder from a user's library")]
[Route("/Users/{UserId}/Items/Root", "GET", Summary = "Gets the root folder from a user's library")]
public class GetRootFolder : IReturn<BaseItemDto>
{
/// <summary>
@ -72,8 +69,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetIntros
/// </summary>
[Route("/Users/{UserId}/Items/{Id}/Intros", "GET")]
[Api(("Gets intros to play before the main media item plays"))]
[Route("/Users/{UserId}/Items/{Id}/Intros", "GET", Summary = "Gets intros to play before the main media item plays")]
public class GetIntros : IReturn<ItemsResult>
{
/// <summary>
@ -94,8 +90,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class MarkFavoriteItem
/// </summary>
[Route("/Users/{UserId}/FavoriteItems/{Id}", "POST")]
[Api(Description = "Marks an item as a favorite")]
[Route("/Users/{UserId}/FavoriteItems/{Id}", "POST", Summary = "Marks an item as a favorite")]
public class MarkFavoriteItem : IReturn<UserItemDataDto>
{
/// <summary>
@ -116,8 +111,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class UnmarkFavoriteItem
/// </summary>
[Route("/Users/{UserId}/FavoriteItems/{Id}", "DELETE")]
[Api(Description = "Unmarks an item as a favorite")]
[Route("/Users/{UserId}/FavoriteItems/{Id}", "DELETE", Summary = "Unmarks an item as a favorite")]
public class UnmarkFavoriteItem : IReturn<UserItemDataDto>
{
/// <summary>
@ -138,8 +132,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class ClearUserItemRating
/// </summary>
[Route("/Users/{UserId}/Items/{Id}/Rating", "DELETE")]
[Api(Description = "Deletes a user's saved personal rating for an item")]
[Route("/Users/{UserId}/Items/{Id}/Rating", "DELETE", Summary = "Deletes a user's saved personal rating for an item")]
public class DeleteUserItemRating : IReturn<UserItemDataDto>
{
/// <summary>
@ -160,8 +153,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class UpdateUserItemRating
/// </summary>
[Route("/Users/{UserId}/Items/{Id}/Rating", "POST")]
[Api(Description = "Updates a user's rating for an item")]
[Route("/Users/{UserId}/Items/{Id}/Rating", "POST", Summary = "Updates a user's rating for an item")]
public class UpdateUserItemRating : IReturn<UserItemDataDto>
{
/// <summary>
@ -189,8 +181,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetLocalTrailers
/// </summary>
[Route("/Users/{UserId}/Items/{Id}/LocalTrailers", "GET")]
[Api(Description = "Gets local trailers for an item")]
[Route("/Users/{UserId}/Items/{Id}/LocalTrailers", "GET", Summary = "Gets local trailers for an item")]
public class GetLocalTrailers : IReturn<List<BaseItemDto>>
{
/// <summary>
@ -211,8 +202,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetSpecialFeatures
/// </summary>
[Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET")]
[Api(Description = "Gets special features for an item")]
[Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET", Summary = "Gets special features for an item")]
public class GetSpecialFeatures : IReturn<List<BaseItemDto>>
{
/// <summary>
@ -280,15 +270,6 @@ namespace MediaBrowser.Api.UserLibrary
private readonly IDtoService _dtoService;
private readonly IUserViewManager _userViewManager;
/// <summary>
/// Initializes a new instance of the <see cref="UserLibraryService" /> class.
/// </summary>
/// <param name="userManager">The user manager.</param>
/// <param name="libraryManager">The library manager.</param>
/// <param name="userDataRepository">The user data repository.</param>
/// <param name="dtoService">The dto service.</param>
/// <param name="userViewManager">The user view manager.</param>
/// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, IUserViewManager userViewManager)
{
_userManager = userManager;

@ -12,7 +12,6 @@ using ServiceStack;
using ServiceStack.Text.Controller;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -59,7 +58,7 @@ namespace MediaBrowser.Api
/// Class DeleteUser
/// </summary>
[Route("/Users/{Id}", "DELETE", Summary = "Deletes a user")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class DeleteUser : IReturnVoid
{
/// <summary>
@ -151,25 +150,16 @@ namespace MediaBrowser.Api
/// Class UpdateUser
/// </summary>
[Route("/Users/{Id}", "POST", Summary = "Updates a user")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class UpdateUser : UserDto, IReturnVoid
{
}
/// <summary>
/// Class CreateUser
/// </summary>
[Route("/Users", "POST", Summary = "Creates a user")]
[Authenticated]
public class CreateUser : UserDto, IReturn<UserDto>
{
}
/// <summary>
/// Class CreateUser
/// </summary>
[Route("/Users/New", "POST", Summary = "Creates a user")]
[Authenticated]
[Authenticated(Roles = "Admin")]
public class CreateUserByName : IReturn<UserDto>
{
[ApiMember(Name = "Name", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
@ -473,24 +463,6 @@ namespace MediaBrowser.Api
user.UpdateConfiguration(dtoUser.Configuration);
}
/// <summary>
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Post(CreateUser request)
{
var dtoUser = request;
var newUser = _userManager.CreateUser(dtoUser.Name).Result;
newUser.UpdateConfiguration(dtoUser.Configuration);
var result = _userManager.GetUserDto(newUser, Request.RemoteIp);
return ToOptimizedResult(result);
}
/// <summary>
/// Posts the specified request.
/// </summary>

@ -15,6 +15,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Api
{
[Route("/Videos/{Id}/AdditionalParts", "GET", Summary = "Gets additional parts for a video.")]
[Authenticated]
public class GetAdditionalParts : IReturn<ItemsResult>
{
[ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
@ -29,6 +30,7 @@ namespace MediaBrowser.Api
}
[Route("/Videos/{Id}/AlternateSources", "DELETE", Summary = "Removes alternate video sources.")]
[Authenticated(Roles = "Admin")]
public class DeleteAlternateSources : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
@ -36,13 +38,13 @@ namespace MediaBrowser.Api
}
[Route("/Videos/MergeVersions", "POST", Summary = "Merges videos into a single record")]
[Authenticated(Roles = "Admin")]
public class MergeVersions : IReturnVoid
{
[ApiMember(Name = "Ids", Description = "Item id list. This allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)]
public string Ids { get; set; }
}
[Authenticated]
public class VideosService : BaseApiService
{
private readonly ILibraryManager _libraryManager;

@ -1618,7 +1618,7 @@ namespace MediaBrowser.Controller.Entities
var parent = user.RootFolder;
list.Add(await GetUserView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false));
//list.Add(await GetUserView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false));
list.Add(await GetUserView(SpecialFolder.LiveTvChannels, user, string.Empty, parent).ConfigureAwait(false));
list.Add(await GetUserView(SpecialFolder.LiveTvRecordingGroups, user, string.Empty, parent).ConfigureAwait(false));

@ -220,8 +220,11 @@
<Compile Include="Net\IHttpResultFactory.cs" />
<Compile Include="Net\IHttpServer.cs" />
<Compile Include="Net\IRestfulService.cs" />
<Compile Include="Net\IServiceRequest.cs" />
<Compile Include="Net\ISessionContext.cs" />
<Compile Include="Net\LoggedAttribute.cs" />
<Compile Include="Net\SecurityException.cs" />
<Compile Include="Net\ServiceStackServiceRequest.cs" />
<Compile Include="Net\StaticResultOptions.cs" />
<Compile Include="News\INewsService.cs" />
<Compile Include="Notifications\INotificationManager.cs" />

@ -5,7 +5,7 @@ using System.Linq;
namespace MediaBrowser.Controller.Net
{
public class AuthenticatedAttribute : Attribute, IHasRequestFilter, IAuthenticated
public class AuthenticatedAttribute : Attribute, IHasRequestFilter, IAuthenticationAttributes
{
public IAuthService AuthService { get; set; }
@ -21,6 +21,12 @@ namespace MediaBrowser.Controller.Net
/// <value><c>true</c> if [escape parental control]; otherwise, <c>false</c>.</value>
public bool EscapeParentalControl { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [allow before startup wizard].
/// </summary>
/// <value><c>true</c> if [allow before startup wizard]; otherwise, <c>false</c>.</value>
public bool AllowBeforeStartupWizard { get; set; }
/// <summary>
/// The request filter is executed before the service.
/// </summary>
@ -29,7 +35,9 @@ namespace MediaBrowser.Controller.Net
/// <param name="requestDto">The request DTO</param>
public void RequestFilter(IRequest request, IResponse response, object requestDto)
{
AuthService.Authenticate(request, response, requestDto, this);
var serviceRequest = new ServiceStackServiceRequest(request);
AuthService.Authenticate(serviceRequest, this);
}
/// <summary>
@ -60,9 +68,10 @@ namespace MediaBrowser.Controller.Net
}
}
public interface IAuthenticated
public interface IAuthenticationAttributes
{
bool EscapeParentalControl { get; }
bool AllowBeforeStartupWizard { get; }
IEnumerable<string> GetRoles();
}

@ -1,12 +1,9 @@
using ServiceStack.Web;

namespace MediaBrowser.Controller.Net
{
public interface IAuthService
{
void Authenticate(IRequest request,
IResponse response,
object requestDto,
IAuthenticated authAttribtues);
void Authenticate(IServiceRequest request,
IAuthenticationAttributes authAttribtues);
}
}

@ -1,5 +1,4 @@
using ServiceStack.Web;

namespace MediaBrowser.Controller.Net
{
public interface IAuthorizationContext
@ -9,6 +8,13 @@ namespace MediaBrowser.Controller.Net
/// </summary>
/// <param name="requestContext">The request context.</param>
/// <returns>AuthorizationInfo.</returns>
AuthorizationInfo GetAuthorizationInfo(IRequest requestContext);
AuthorizationInfo GetAuthorizationInfo(object requestContext);
/// <summary>
/// Gets the authorization information.
/// </summary>
/// <param name="requestContext">The request context.</param>
/// <returns>AuthorizationInfo.</returns>
AuthorizationInfo GetAuthorizationInfo(IServiceRequest requestContext);
}
}

@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Collections.Specialized;
namespace MediaBrowser.Controller.Net
{
public interface IServiceRequest
{
object OriginalRequest { get; }
string RemoteIp { get; }
NameValueCollection Headers { get; }
NameValueCollection QueryString { get; }
IDictionary<string,object> Items { get; }
void AddResponseHeader(string name, string value);
}
}

@ -1,13 +1,14 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Session;
using ServiceStack.Web;
namespace MediaBrowser.Controller.Net
{
public interface ISessionContext
{
SessionInfo GetSession(IRequest requestContext);
User GetUser(IRequest requestContext);
SessionInfo GetSession(object requestContext);
User GetUser(object requestContext);
SessionInfo GetSession(IServiceRequest requestContext);
User GetUser(IServiceRequest requestContext);
}
}

@ -22,8 +22,10 @@ namespace MediaBrowser.Controller.Net
/// <param name="requestDto">The request DTO</param>
public void RequestFilter(IRequest request, IResponse response, object requestDto)
{
var serviceRequest = new ServiceStackServiceRequest(request);
//This code is executed before the service
var auth = AuthorizationContext.GetAuthorizationInfo(request);
var auth = AuthorizationContext.GetAuthorizationInfo(serviceRequest);
if (auth != null)
{

@ -0,0 +1,21 @@
using System;
namespace MediaBrowser.Controller.Net
{
public class SecurityException : Exception
{
public SecurityException(string message)
: base(message)
{
}
public SecurityExceptionType SecurityExceptionType { get; set; }
}
public enum SecurityExceptionType
{
Unauthenticated = 0,
ParentalControl = 1
}
}

@ -0,0 +1,62 @@
using ServiceStack.Web;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
namespace MediaBrowser.Controller.Net
{
public class ServiceStackServiceRequest : IServiceRequest
{
private readonly IRequest _request;
public ServiceStackServiceRequest(IRequest request)
{
_request = request;
}
public object OriginalRequest
{
get { return _request; }
}
public string RemoteIp
{
get { return _request.RemoteIp; }
}
private NameValueCollection _headers;
public NameValueCollection Headers
{
get { return _headers ?? (_headers = Get(_request.Headers)); }
}
private NameValueCollection _query;
public NameValueCollection QueryString
{
get { return _query ?? (_query = Get(_request.QueryString)); }
}
private NameValueCollection Get(INameValueCollection coll)
{
var nv = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
foreach (var key in coll.AllKeys)
{
nv[key] = coll[key];
}
return nv;
//return coll.ToNameValueCollection();
}
public IDictionary<string, object> Items
{
get { return _request.Items; }
}
public void AddResponseHeader(string name, string value)
{
_request.Response.AddHeader(name, value);
}
}
}

@ -255,12 +255,6 @@ namespace MediaBrowser.Controller.Session
/// <returns>SessionInfo.</returns>
SessionInfo GetSession(string deviceId, string client, string version);
/// <summary>
/// Validates the security token.
/// </summary>
/// <param name="accessToken">The access token.</param>
void ValidateSecurityToken(string accessToken);
/// <summary>
/// Logouts the specified access token.
/// </summary>

@ -170,7 +170,7 @@ namespace MediaBrowser.Model.Configuration
public PeopleMetadataOptions PeopleMetadataOptions { get; set; }
public bool FindInternetTrailers { get; set; }
public string[] InsecureApps6 { get; set; }
public string[] InsecureApps7 { get; set; }
public bool SaveMetadataHidden { get; set; }
@ -222,19 +222,16 @@ namespace MediaBrowser.Model.Configuration
PeopleMetadataOptions = new PeopleMetadataOptions();
InsecureApps6 = new[]
InsecureApps7 = new[]
{
"Roku",
"Chromecast",
"iOS",
"Windows Phone",
"Windows RT",
"Xbmc",
"Unknown app",
"MediaPortal",
"Media Portal",
"iPad",
"iPhone"
"iPhone",
"Roku"
};
MetadataOptions = new[]

@ -91,7 +91,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{typeof (ResourceNotFoundException), 404},
{typeof (FileNotFoundException), 404},
{typeof (DirectoryNotFoundException), 404},
{typeof (Implementations.Security.AuthenticationException), 401},
{typeof (SecurityException), 401},
{typeof (UnauthorizedAccessException), 401}
};

@ -1,13 +1,11 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Connect;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using ServiceStack;
using ServiceStack.Auth;
using ServiceStack.Web;
using MediaBrowser.Controller.Security;
using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Server.Implementations.HttpServer.Security
@ -16,61 +14,43 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
{
private readonly IServerConfigurationManager _config;
public AuthService(IUserManager userManager, ISessionManager sessionManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, IConnectManager connectManager)
public AuthService(IUserManager userManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, IConnectManager connectManager)
{
AuthorizationContext = authorizationContext;
_config = config;
ConnectManager = connectManager;
SessionManager = sessionManager;
UserManager = userManager;
}
public IUserManager UserManager { get; private set; }
public ISessionManager SessionManager { get; private set; }
public IAuthorizationContext AuthorizationContext { get; private set; }
public IConnectManager ConnectManager { get; private set; }
/// <summary>
/// Restrict authentication to a specific <see cref="IAuthProvider"/>.
/// For example, if this attribute should only permit access
/// if the user is authenticated with <see cref="BasicAuthProvider"/>,
/// you should set this property to <see cref="BasicAuthProvider.Name"/>.
/// </summary>
public string Provider { get; set; }
/// <summary>
/// Redirect the client to a specific URL if authentication failed.
/// If this property is null, simply `401 Unauthorized` is returned.
/// </summary>
public string HtmlRedirect { get; set; }
public void Authenticate(IRequest request,
IResponse response,
object requestDto,
IAuthenticated authAttribtues)
public void Authenticate(IServiceRequest request,
IAuthenticationAttributes authAttribtues)
{
if (HostContext.HasValidAuthSecret(request))
return;
//ExecuteBasic(req, res, requestDto); //first check if session is authenticated
//if (res.IsClosed) return; //AuthenticateAttribute already closed the request (ie auth failed)
ValidateUser(request, response, authAttribtues);
ValidateUser(request, authAttribtues);
}
private void ValidateUser(IRequest req, IResponse response, IAuthenticated authAttribtues)
private void ValidateUser(IServiceRequest request,
IAuthenticationAttributes authAttribtues)
{
// This code is executed before the service
var auth = AuthorizationContext.GetAuthorizationInfo(req);
var auth = AuthorizationContext.GetAuthorizationInfo(request);
if (!string.IsNullOrWhiteSpace(auth.Token) ||
!_config.Configuration.InsecureApps6.Contains(auth.Client ?? string.Empty, StringComparer.OrdinalIgnoreCase))
if (!IsExemptFromAuthenticationToken(auth, authAttribtues))
{
var valid = IsValidConnectKey(auth.Token);
if (!valid)
{
SessionManager.ValidateSecurityToken(auth.Token);
ValidateSecurityToken(request, auth.Token);
}
}
@ -80,45 +60,83 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
if (user == null & !string.IsNullOrWhiteSpace(auth.UserId))
{
throw new ArgumentException("User with Id " + auth.UserId + " not found");
throw new SecurityException("User with Id " + auth.UserId + " not found");
}
if (user != null)
{
if (user.Configuration.IsDisabled)
{
throw new AuthenticationException("User account has been disabled.");
throw new SecurityException("User account has been disabled.")
{
SecurityExceptionType = SecurityExceptionType.Unauthenticated
};
}
if (!user.Configuration.IsAdministrator &&
!authAttribtues.EscapeParentalControl &&
!user.IsParentalScheduleAllowed())
{
response.AddHeader("X-Application-Error-Code", "ParentalControl");
throw new AuthenticationException("This user account is not allowed access at this time.");
request.AddResponseHeader("X-Application-Error-Code", "ParentalControl");
throw new SecurityException("This user account is not allowed access at this time.")
{
SecurityExceptionType = SecurityExceptionType.ParentalControl
};
}
}
var roles = authAttribtues.GetRoles().ToList();
if (!IsExemptFromRoles(auth, authAttribtues))
{
var roles = authAttribtues.GetRoles().ToList();
ValidateRoles(roles, user);
}
}
private bool IsExemptFromAuthenticationToken(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues)
{
if (!_config.Configuration.IsStartupWizardCompleted &&
authAttribtues.AllowBeforeStartupWizard)
{
return true;
}
return _config.Configuration.InsecureApps7.Contains(auth.Client ?? string.Empty,
StringComparer.OrdinalIgnoreCase);
}
private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues)
{
if (!_config.Configuration.IsStartupWizardCompleted &&
authAttribtues.AllowBeforeStartupWizard)
{
return true;
}
return false;
}
private void ValidateRoles(List<string> roles, User user)
{
if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase))
{
if (user == null || !user.Configuration.IsAdministrator)
{
throw new ArgumentException("Administrative access is required for this request.");
throw new SecurityException("User does not have admin access.")
{
SecurityExceptionType = SecurityExceptionType.Unauthenticated
};
}
}
if (!string.IsNullOrWhiteSpace(auth.DeviceId) &&
!string.IsNullOrWhiteSpace(auth.Client) &&
!string.IsNullOrWhiteSpace(auth.Device))
if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase))
{
SessionManager.LogSessionActivity(auth.Client,
auth.Version,
auth.DeviceId,
auth.Device,
req.RemoteIp,
user);
if (user == null || !user.Configuration.EnableContentDeletion)
{
throw new SecurityException("User does not have delete access.")
{
SecurityExceptionType = SecurityExceptionType.Unauthenticated
};
}
}
}
@ -132,40 +150,34 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
return ConnectManager.IsAuthorizationTokenValid(token);
}
protected bool DoHtmlRedirectIfConfigured(IRequest req, IResponse res, bool includeRedirectParam = false)
private void ValidateSecurityToken(IServiceRequest request, string token)
{
var htmlRedirect = this.HtmlRedirect ?? AuthenticateService.HtmlRedirect;
if (htmlRedirect != null && req.ResponseContentType.MatchesContentType(MimeTypes.Html))
if (string.IsNullOrWhiteSpace(token))
{
DoHtmlRedirect(htmlRedirect, req, res, includeRedirectParam);
return true;
throw new SecurityException("Access token is invalid or expired.");
}
return false;
}
public static void DoHtmlRedirect(string redirectUrl, IRequest req, IResponse res, bool includeRedirectParam)
{
var url = req.ResolveAbsoluteUrl(redirectUrl);
if (includeRedirectParam)
var info = (AuthenticationInfo)request.Items["OriginalAuthenticationInfo"];
if (info == null)
{
var absoluteRequestPath = req.ResolveAbsoluteUrl("~" + req.PathInfo + ToQueryString(req.QueryString));
url = url.AddQueryParam(HostContext.ResolveLocalizedString(LocalizedStrings.Redirect), absoluteRequestPath);
throw new SecurityException("Access token is invalid or expired.");
}
res.RedirectToUrl(url);
}
private static string ToQueryString(INameValueCollection queryStringCollection)
{
return ToQueryString((NameValueCollection)queryStringCollection.Original);
}
if (!info.IsActive)
{
throw new SecurityException("Access token has expired.");
}
private static string ToQueryString(NameValueCollection queryStringCollection)
{
if (queryStringCollection == null || queryStringCollection.Count == 0)
return String.Empty;
//if (!string.IsNullOrWhiteSpace(info.UserId))
//{
// var user = _userManager.GetUserById(info.UserId);
return "?" + queryStringCollection.ToFormUrlEncoded();
// if (user == null || user.Configuration.IsDisabled)
// {
// throw new SecurityException("User account has been disabled.");
// }
//}
}
}
}

@ -1,14 +1,35 @@
using System;
using System.Collections.Generic;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using ServiceStack.Web;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Server.Implementations.HttpServer.Security
{
public class AuthorizationContext : IAuthorizationContext
{
public AuthorizationInfo GetAuthorizationInfo(IRequest requestContext)
private readonly IAuthenticationRepository _authRepo;
public AuthorizationContext(IAuthenticationRepository authRepo)
{
_authRepo = authRepo;
}
public AuthorizationInfo GetAuthorizationInfo(object requestContext)
{
var req = new ServiceStackServiceRequest((IRequest)requestContext);
return GetAuthorizationInfo(req);
}
public AuthorizationInfo GetAuthorizationInfo(IServiceRequest requestContext)
{
object cached;
if (requestContext.Items.TryGetValue("AuthorizationInfo", out cached))
{
return (AuthorizationInfo)cached;
}
return GetAuthorization(requestContext);
}
@ -17,7 +38,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
/// </summary>
/// <param name="httpReq">The HTTP req.</param>
/// <returns>Dictionary{System.StringSystem.String}.</returns>
private AuthorizationInfo GetAuthorization(IRequest httpReq)
private AuthorizationInfo GetAuthorization(IServiceRequest httpReq)
{
var auth = GetAuthorizationDictionary(httpReq);
@ -29,7 +50,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
if (auth != null)
{
// TODO: Remove this
auth.TryGetValue("UserId", out userId);
auth.TryGetValue("DeviceId", out deviceId);
auth.TryGetValue("Device", out device);
auth.TryGetValue("Client", out client);
@ -84,7 +107,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
}
}
return new AuthorizationInfo
var info = new AuthorizationInfo
{
Client = client,
Device = device,
@ -93,6 +116,26 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
Version = version,
Token = token
};
if (!string.IsNullOrWhiteSpace(token))
{
var result = _authRepo.Get(new AuthenticationInfoQuery
{
AccessToken = token
});
var tokenInfo = result.Items.FirstOrDefault();
if (tokenInfo != null)
{
info.UserId = tokenInfo.UserId;
}
httpReq.Items["OriginalAuthenticationInfo"] = tokenInfo;
}
httpReq.Items["AuthorizationInfo"] = info;
return info;
}
/// <summary>
@ -100,7 +143,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
/// </summary>
/// <param name="httpReq">The HTTP req.</param>
/// <returns>Dictionary{System.StringSystem.String}.</returns>
private Dictionary<string, string> GetAuthorizationDictionary(IRequest httpReq)
private Dictionary<string, string> GetAuthorizationDictionary(IServiceRequest httpReq)
{
var auth = httpReq.Headers["Authorization"];

@ -19,18 +19,30 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
_sessionManager = sessionManager;
}
public SessionInfo GetSession(IRequest requestContext)
public SessionInfo GetSession(IServiceRequest requestContext)
{
var authorization = _authContext.GetAuthorizationInfo(requestContext);
return _sessionManager.GetSession(authorization.DeviceId, authorization.Client, authorization.Version);
}
public User GetUser(IRequest requestContext)
public User GetUser(IServiceRequest requestContext)
{
var session = GetSession(requestContext);
return session == null || !session.UserId.HasValue ? null : _userManager.GetUserById(session.UserId.Value);
}
public SessionInfo GetSession(object requestContext)
{
var req = new ServiceStackServiceRequest((IRequest)requestContext);
return GetSession(req);
}
public User GetUser(object requestContext)
{
var req = new ServiceStackServiceRequest((IRequest)requestContext);
return GetUser(req);
}
}
}

@ -8,6 +8,7 @@ using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
@ -180,12 +181,12 @@ namespace MediaBrowser.Server.Implementations.Library
if (user == null)
{
throw new AuthenticationException("Invalid username or password entered.");
throw new SecurityException("Invalid username or password entered.");
}
if (user.Configuration.IsDisabled)
{
throw new AuthenticationException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name));
throw new SecurityException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name));
}
var success = false;

@ -247,7 +247,6 @@
<Compile Include="ScheduledTasks\RefreshIntrosTask.cs" />
<Compile Include="ScheduledTasks\RefreshMediaLibraryTask.cs" />
<Compile Include="ScheduledTasks\SystemUpdateTask.cs" />
<Compile Include="Security\AuthenticationException.cs" />
<Compile Include="Security\AuthenticationRepository.cs" />
<Compile Include="Security\EncryptionManager.cs" />
<Compile Include="ServerApplicationPaths.cs" />

@ -1,16 +0,0 @@
using System;
namespace MediaBrowser.Server.Implementations.Security
{
public class AuthenticationException : Exception
{
public AuthenticationException(string message)
: base(message)
{
}
public AuthenticationException()
{
}
}
}

@ -11,10 +11,10 @@ using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Connect;
using MediaBrowser.Model.Devices;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
@ -23,7 +23,6 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Session;
using MediaBrowser.Model.Users;
using MediaBrowser.Server.Implementations.Security;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@ -253,11 +252,6 @@ namespace MediaBrowser.Server.Implementations.Session
throw new ArgumentNullException("deviceName");
}
if (user != null && user.Configuration.IsDisabled)
{
throw new AuthenticationException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name));
}
var activityDate = DateTime.UtcNow;
var userId = user == null ? (Guid?)null : user.Id;
@ -1261,49 +1255,11 @@ namespace MediaBrowser.Server.Implementations.Session
}
}
public void ValidateSecurityToken(string token)
{
if (string.IsNullOrWhiteSpace(token))
{
throw new AuthenticationException();
}
var result = _authRepo.Get(new AuthenticationInfoQuery
{
AccessToken = token
});
var info = result.Items.FirstOrDefault();
if (info == null)
{
throw new AuthenticationException();
}
if (!info.IsActive)
{
throw new AuthenticationException("Access token has expired.");
}
if (!string.IsNullOrWhiteSpace(info.UserId))
{
var user = _userManager.GetUserById(info.UserId);
if (user == null || user.Configuration.IsDisabled)
{
throw new AuthenticationException("User account has been disabled.");
}
}
}
/// <summary>
/// Authenticates the new session.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>Task{SessionInfo}.</returns>
/// <exception cref="AuthenticationException">Invalid user or password entered.</exception>
/// <exception cref="System.UnauthorizedAccessException">Invalid user or password entered.</exception>
/// <exception cref="UnauthorizedAccessException">Invalid user or password entered.</exception>
public async Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request)
{
var user = _userManager.Users
@ -1315,7 +1271,7 @@ namespace MediaBrowser.Server.Implementations.Session
{
EventHelper.FireEventIfNotNull(AuthenticationFailed, this, new GenericEventArgs<AuthenticationRequest>(request), _logger);
throw new AuthenticationException("Invalid user or password entered.");
throw new UnauthorizedAccessException("Invalid user or password entered.");
}
var token = await GetAuthorizationToken(user.Id.ToString("N"), request.DeviceId, request.App, request.DeviceName).ConfigureAwait(false);

@ -496,10 +496,10 @@ namespace MediaBrowser.Server.Startup.Common
RegisterSingleInstance(activityLogRepo);
RegisterSingleInstance<IActivityManager>(new ActivityManager(LogManager.GetLogger("ActivityManager"), activityLogRepo, UserManager));
var authContext = new AuthorizationContext();
var authContext = new AuthorizationContext(AuthenticationRepository);
RegisterSingleInstance<IAuthorizationContext>(authContext);
RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
RegisterSingleInstance<IAuthService>(new AuthService(UserManager, SessionManager, authContext, ServerConfigurationManager, ConnectManager));
RegisterSingleInstance<IAuthService>(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager));
RegisterSingleInstance<ISubtitleEncoder>(new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer));
@ -534,6 +534,8 @@ namespace MediaBrowser.Server.Startup.Common
var info = await new FFMpegDownloader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager)
.GetFFMpegInfo(NativeApp.Environment, _startupOptions, progress).ConfigureAwait(false);
new FFmpegValidator(Logger, ApplicationPaths).Validate(info);
MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), JsonSerializer, info.EncoderPath, info.ProbePath, info.Version);
RegisterSingleInstance(MediaEncoder);
}

@ -0,0 +1,116 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Model.Logging;
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
namespace MediaBrowser.Server.Startup.Common.FFMpeg
{
public class FFmpegValidator
{
private readonly ILogger _logger;
private readonly IApplicationPaths _appPaths;
public FFmpegValidator(ILogger logger, IApplicationPaths appPaths)
{
_logger = logger;
_appPaths = appPaths;
}
public void Validate(FFMpegInfo info)
{
_logger.Info("FFMpeg: {0}", info.EncoderPath);
_logger.Info("FFProbe: {0}", info.ProbePath);
var fileInfo = new FileInfo(info.EncoderPath);
var cachePath = Path.Combine(_appPaths.CachePath, fileInfo.Length.ToString(CultureInfo.InvariantCulture).GetMD5().ToString("N"));
if (!File.Exists(cachePath))
{
ValidateCodecs(info.EncoderPath);
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
File.WriteAllText(cachePath, string.Empty, Encoding.UTF8);
}
}
private void ValidateCodecs(string path)
{
var output = GetOutput(path, "-encoders");
var required = new[]
{
"libx264",
"mpeg4",
"msmpeg4",
"libvpx",
//"libvpx-vp9",
"aac",
"ac3",
"libmp3lame",
"libvorbis",
"srt"
};
foreach (var encoder in required)
{
var srch = " " + encoder + " ";
if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1)
{
throw new ArgumentException("ffmpeg is missing encoder " + encoder);
}
}
}
private string GetOutput(string path, string arguments)
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
FileName = path,
Arguments = arguments,
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
using (process)
{
process.Start();
try
{
process.BeginErrorReadLine();
using (var reader = new StreamReader(process.StandardOutput.BaseStream))
{
return reader.ReadToEnd();
}
}
catch
{
// Hate having to do this
try
{
process.Kill();
}
catch (Exception ex1)
{
_logger.ErrorException("Error killing ffmpeg", ex1);
}
throw;
}
}
}
}
}

@ -59,6 +59,7 @@
<Compile Include="FFMpeg\FFMpegDownloader.cs" />
<Compile Include="FFMpeg\FFMpegDownloadInfo.cs" />
<Compile Include="FFMpeg\FFMpegInfo.cs" />
<Compile Include="FFMpeg\FFmpegValidator.cs" />
<Compile Include="INativeApp.cs" />
<Compile Include="Migrations\DeprecatePlugins.cs" />
<Compile Include="Migrations\IVersionMigration.cs" />

@ -195,8 +195,7 @@ namespace MediaBrowser.ServerApplication
/// <param name="appPaths">The app paths.</param>
private static void BeginLog(ILogger logger, IApplicationPaths appPaths)
{
logger.Info("Media Browser Server started");
ApplicationHost.LogEnvironmentInfo(logger, appPaths);
ApplicationHost.LogEnvironmentInfo(logger, appPaths, true);
}
private static readonly TaskCompletionSource<bool> ApplicationTaskCompletionSource = new TaskCompletionSource<bool>();

Loading…
Cancel
Save