aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs34
-rw-r--r--MediaBrowser.Api/ConfigurationService.cs1
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs9
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs3
-rw-r--r--MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs2
-rw-r--r--MediaBrowser.Api/SessionsService.cs18
-rw-r--r--MediaBrowser.Api/SystemService.cs1
-rw-r--r--MediaBrowser.Api/UserService.cs32
-rw-r--r--MediaBrowser.Controller/Channels/ChannelItemInfo.cs13
-rw-r--r--MediaBrowser.Controller/Collections/CollectionEvents.cs37
-rw-r--r--MediaBrowser.Controller/Collections/ICollectionManager.cs15
-rw-r--r--MediaBrowser.Controller/Dto/IDtoService.cs7
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj4
-rw-r--r--MediaBrowser.Controller/Providers/IMetadataProvider.cs1
-rw-r--r--MediaBrowser.Controller/Security/AuthenticationInfo.cs61
-rw-r--r--MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs42
-rw-r--r--MediaBrowser.Controller/Security/IAuthenticationRepository.cs39
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs25
-rw-r--r--MediaBrowser.Controller/Session/SessionInfo.cs2
-rw-r--r--MediaBrowser.LocalMetadata/BaseXmlProvider.cs10
-rw-r--r--MediaBrowser.Model/ApiClient/IApiClient.cs19
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs2
-rw-r--r--MediaBrowser.Model/Users/AuthenticationResult.cs2
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Manager/ProviderUtils.cs2
-rw-r--r--MediaBrowser.Providers/TV/MovieDbEpisodeImageProvider.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs3
-rw-r--r--MediaBrowser.Server.Implementations/Collections/CollectionManager.cs57
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs48
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj1
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs338
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs159
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs20
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs2
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs10
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/SeasonXmlSaver.cs13
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/XmlSaverHelpers.cs22
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec4
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
41 files changed, 933 insertions, 136 deletions
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index 8e6ca4401..f255339bc 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -37,7 +37,7 @@ namespace MediaBrowser.Api
private readonly ISessionManager _sessionManager;
- public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1,1);
+ public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1);
/// <summary>
/// Initializes a new instance of the <see cref="ApiEntryPoint" /> class.
@@ -102,7 +102,7 @@ namespace MediaBrowser.Api
{
var jobCount = _activeTranscodingJobs.Count;
- Parallel.ForEach(_activeTranscodingJobs.ToList(), j => KillTranscodingJob(j, FileDeleteMode.All));
+ Parallel.ForEach(_activeTranscodingJobs.ToList(), j => KillTranscodingJob(j, path => true));
// Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
if (jobCount > 0)
@@ -295,17 +295,18 @@ namespace MediaBrowser.Api
{
var job = (TranscodingJob)state;
- KillTranscodingJob(job, FileDeleteMode.All);
+ KillTranscodingJob(job, path => true);
}
/// <summary>
/// Kills the single transcoding job.
/// </summary>
/// <param name="deviceId">The device id.</param>
- /// <param name="deleteMode">The delete mode.</param>
+ /// <param name="delete">The delete.</param>
/// <param name="acquireLock">if set to <c>true</c> [acquire lock].</param>
+ /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">sourcePath</exception>
- internal async Task KillTranscodingJobs(string deviceId, FileDeleteMode deleteMode, bool acquireLock)
+ internal async Task KillTranscodingJobs(string deviceId, Func<string, bool> delete, bool acquireLock)
{
if (string.IsNullOrEmpty(deviceId))
{
@@ -330,12 +331,12 @@ namespace MediaBrowser.Api
{
await TranscodingStartLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
}
-
+
try
{
foreach (var job in jobs)
{
- KillTranscodingJob(job, deleteMode);
+ KillTranscodingJob(job, delete);
}
}
finally
@@ -352,10 +353,11 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="deviceId">The device identifier.</param>
/// <param name="type">The type.</param>
- /// <param name="deleteMode">The delete mode.</param>
+ /// <param name="delete">The delete.</param>
/// <param name="acquireLock">if set to <c>true</c> [acquire lock].</param>
+ /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">deviceId</exception>
- internal async Task KillTranscodingJobs(string deviceId, TranscodingJobType type, FileDeleteMode deleteMode, bool acquireLock)
+ internal async Task KillTranscodingJobs(string deviceId, TranscodingJobType type, Func<string, bool> delete, bool acquireLock)
{
if (string.IsNullOrEmpty(deviceId))
{
@@ -385,7 +387,7 @@ namespace MediaBrowser.Api
{
foreach (var job in jobs)
{
- KillTranscodingJob(job, deleteMode);
+ KillTranscodingJob(job, delete);
}
}
finally
@@ -401,8 +403,8 @@ namespace MediaBrowser.Api
/// Kills the transcoding job.
/// </summary>
/// <param name="job">The job.</param>
- /// <param name="deleteMode">The delete mode.</param>
- private void KillTranscodingJob(TranscodingJob job, FileDeleteMode deleteMode)
+ /// <param name="delete">The delete.</param>
+ private void KillTranscodingJob(TranscodingJob job, Func<string, bool> delete)
{
lock (_activeTranscodingJobs)
{
@@ -454,7 +456,7 @@ namespace MediaBrowser.Api
}
}
- if (deleteMode == FileDeleteMode.All)
+ if (delete(job.Path))
{
DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
}
@@ -593,10 +595,4 @@ namespace MediaBrowser.Api
/// </summary>
Hls
}
-
- public enum FileDeleteMode
- {
- None,
- All
- }
}
diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs
index e628c5f7a..6710461ad 100644
--- a/MediaBrowser.Api/ConfigurationService.cs
+++ b/MediaBrowser.Api/ConfigurationService.cs
@@ -18,6 +18,7 @@ namespace MediaBrowser.Api
/// Class GetConfiguration
/// </summary>
[Route("/System/Configuration", "GET", Summary = "Gets application configuration")]
+ [Authenticated]
public class GetConfiguration : IReturn<ServerConfiguration>
{
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 8a65e2b56..8eff75533 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -22,7 +22,8 @@ namespace MediaBrowser.Api.Playback.Hls
/// </summary>
public abstract class BaseHlsService : BaseStreamingService
{
- protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
+ protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder)
+ : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
{
}
@@ -103,8 +104,8 @@ namespace MediaBrowser.Api.Playback.Hls
}
else
{
- await ApiEntryPoint.Instance.KillTranscodingJobs(state.Request.DeviceId, TranscodingJobType.Hls, FileDeleteMode.All, false).ConfigureAwait(false);
-
+ await ApiEntryPoint.Instance.KillTranscodingJobs(state.Request.DeviceId, TranscodingJobType.Hls, p => true, false).ConfigureAwait(false);
+
// If the playlist doesn't already exist, startup ffmpeg
try
{
@@ -252,7 +253,7 @@ namespace MediaBrowser.Api.Playback.Hls
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
{
var hlsVideoRequest = state.VideoRequest as GetHlsVideoStream;
-
+
var itsOffsetMs = hlsVideoRequest == null
? 0
: hlsVideoRequest.TimeStampOffsetMs;
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index 6c09f00a1..07aaf5f86 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -127,8 +127,7 @@ namespace MediaBrowser.Api.Playback.Hls
// If the playlist doesn't already exist, startup ffmpeg
try
{
- // TODO: Delete files from other jobs, but not this one
- await ApiEntryPoint.Instance.KillTranscodingJobs(state.Request.DeviceId, TranscodingJobType.Hls, FileDeleteMode.None, false).ConfigureAwait(false);
+ await ApiEntryPoint.Instance.KillTranscodingJobs(state.Request.DeviceId, TranscodingJobType.Hls, p => !string.Equals(p, playlistPath, StringComparison.OrdinalIgnoreCase), false).ConfigureAwait(false);
if (currentTranscodingIndex.HasValue)
{
diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
index 3848cb2de..f28352588 100644
--- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
+++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
@@ -74,7 +74,7 @@ namespace MediaBrowser.Api.Playback.Hls
public void Delete(StopEncodingProcess request)
{
- var task = ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, FileDeleteMode.All, true);
+ var task = ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, path => true, true);
Task.WaitAll(task);
}
diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs
index f4651601b..ed7db626f 100644
--- a/MediaBrowser.Api/SessionsService.cs
+++ b/MediaBrowser.Api/SessionsService.cs
@@ -213,6 +213,7 @@ namespace MediaBrowser.Api
}
[Route("/Sessions/Capabilities", "POST", Summary = "Updates capabilities for a device")]
+ [Authenticated]
public class PostCapabilities : IReturnVoid
{
/// <summary>
@@ -235,6 +236,11 @@ namespace MediaBrowser.Api
public bool SupportsMediaControl { get; set; }
}
+ [Route("/Sessions/Logout", "POST", Summary = "Reports that a session has ended")]
+ public class ReportSessionEnded : IReturnVoid
+ {
+ }
+
/// <summary>
/// Class SessionsService
/// </summary>
@@ -246,16 +252,26 @@ namespace MediaBrowser.Api
private readonly ISessionManager _sessionManager;
private readonly IUserManager _userManager;
+ private readonly IAuthorizationContext _authContext;
/// <summary>
/// Initializes a new instance of the <see cref="SessionsService" /> class.
/// </summary>
/// <param name="sessionManager">The session manager.</param>
/// <param name="userManager">The user manager.</param>
- public SessionsService(ISessionManager sessionManager, IUserManager userManager)
+ public SessionsService(ISessionManager sessionManager, IUserManager userManager, IAuthorizationContext authContext)
{
_sessionManager = sessionManager;
_userManager = userManager;
+ _authContext = authContext;
+ }
+
+
+ public void Post(ReportSessionEnded request)
+ {
+ var auth = _authContext.GetAuthorizationInfo(Request);
+
+ _sessionManager.Logout(auth.Token);
}
/// <summary>
diff --git a/MediaBrowser.Api/SystemService.cs b/MediaBrowser.Api/SystemService.cs
index 6f2e83a79..f336736be 100644
--- a/MediaBrowser.Api/SystemService.cs
+++ b/MediaBrowser.Api/SystemService.cs
@@ -15,6 +15,7 @@ namespace MediaBrowser.Api
/// Class GetSystemInfo
/// </summary>
[Route("/System/Info", "GET", Summary = "Gets information about the server")]
+ [Authenticated]
public class GetSystemInfo : IReturn<SystemInfo>
{
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index cda489c94..bcaf80d69 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -4,7 +4,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Users;
using ServiceStack;
using ServiceStack.Text.Controller;
@@ -19,6 +18,7 @@ namespace MediaBrowser.Api
/// Class GetUsers
/// </summary>
[Route("/Users", "GET", Summary = "Gets a list of users")]
+ [Authenticated]
public class GetUsers : IReturn<List<UserDto>>
{
[ApiMember(Name = "IsHidden", Description = "Optional filter by IsHidden=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
@@ -37,6 +37,7 @@ namespace MediaBrowser.Api
/// Class GetUser
/// </summary>
[Route("/Users/{Id}", "GET", Summary = "Gets a user by Id")]
+ [Authenticated]
public class GetUser : IReturn<UserDto>
{
/// <summary>
@@ -160,11 +161,6 @@ namespace MediaBrowser.Api
public class UserService : BaseApiService, IHasAuthorization
{
/// <summary>
- /// The _XML serializer
- /// </summary>
- private readonly IXmlSerializer _xmlSerializer;
-
- /// <summary>
/// The _user manager
/// </summary>
private readonly IUserManager _userManager;
@@ -176,19 +172,12 @@ namespace MediaBrowser.Api
/// <summary>
/// Initializes a new instance of the <see cref="UserService" /> class.
/// </summary>
- /// <param name="xmlSerializer">The XML serializer.</param>
/// <param name="userManager">The user manager.</param>
/// <param name="dtoService">The dto service.</param>
+ /// <param name="sessionMananger">The session mananger.</param>
/// <exception cref="System.ArgumentNullException">xmlSerializer</exception>
- public UserService(IXmlSerializer xmlSerializer, IUserManager userManager, IDtoService dtoService, ISessionManager sessionMananger)
- : base()
+ public UserService(IUserManager userManager, IDtoService dtoService, ISessionManager sessionMananger)
{
- if (xmlSerializer == null)
- {
- throw new ArgumentNullException("xmlSerializer");
- }
-
- _xmlSerializer = xmlSerializer;
_userManager = userManager;
_dtoService = dtoService;
_sessionMananger = sessionMananger;
@@ -196,6 +185,11 @@ namespace MediaBrowser.Api
public object Get(GetPublicUsers request)
{
+ if (!Request.IsLocal && !_sessionMananger.IsLocal(Request.RemoteIp))
+ {
+ return ToOptimizedResult(new List<UserDto>());
+ }
+
return Get(new GetUsers
{
IsHidden = false,
@@ -368,9 +362,15 @@ namespace MediaBrowser.Api
{
throw new ArgumentException("There must be at least one enabled user in the system.");
}
+
+ var revokeTask = _sessionMananger.RevokeUserTokens(user.Id.ToString("N"));
+
+ Task.WaitAll(revokeTask);
}
- var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ? _userManager.UpdateUser(user) : _userManager.RenameUser(user, dtoUser.Name);
+ var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ?
+ _userManager.UpdateUser(user) :
+ _userManager.RenameUser(user, dtoUser.Name);
Task.WaitAll(task);
diff --git a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
index 707807bd5..3c7df91c1 100644
--- a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
+++ b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
@@ -10,6 +10,8 @@ namespace MediaBrowser.Controller.Channels
{
public string Name { get; set; }
+ public string SeriesName { get; set; }
+
public string Id { get; set; }
public ChannelItemType Type { get; set; }
@@ -28,8 +30,6 @@ namespace MediaBrowser.Controller.Channels
public long? RunTimeTicks { get; set; }
- public bool IsInfiniteStream { get; set; }
-
public string ImageUrl { get; set; }
public ChannelMediaType MediaType { get; set; }
@@ -43,9 +43,14 @@ namespace MediaBrowser.Controller.Channels
public int? ProductionYear { get; set; }
public DateTime? DateCreated { get; set; }
-
+
+ public int? IndexNumber { get; set; }
+ public int? ParentIndexNumber { get; set; }
+
public List<ChannelMediaInfo> MediaSources { get; set; }
-
+
+ public bool IsInfiniteStream { get; set; }
+
public ChannelItemInfo()
{
MediaSources = new List<ChannelMediaInfo>();
diff --git a/MediaBrowser.Controller/Collections/CollectionEvents.cs b/MediaBrowser.Controller/Collections/CollectionEvents.cs
new file mode 100644
index 000000000..80f66a444
--- /dev/null
+++ b/MediaBrowser.Controller/Collections/CollectionEvents.cs
@@ -0,0 +1,37 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Collections
+{
+ public class CollectionCreatedEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Gets or sets the collection.
+ /// </summary>
+ /// <value>The collection.</value>
+ public BoxSet Collection { get; set; }
+
+ /// <summary>
+ /// Gets or sets the options.
+ /// </summary>
+ /// <value>The options.</value>
+ public CollectionCreationOptions Options { get; set; }
+ }
+
+ public class CollectionModifiedEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Gets or sets the collection.
+ /// </summary>
+ /// <value>The collection.</value>
+ public BoxSet Collection { get; set; }
+
+ /// <summary>
+ /// Gets or sets the items changed.
+ /// </summary>
+ /// <value>The items changed.</value>
+ public List<BaseItem> ItemsChanged { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs
index fdb2a4975..9130f68d4 100644
--- a/MediaBrowser.Controller/Collections/ICollectionManager.cs
+++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs
@@ -9,6 +9,21 @@ namespace MediaBrowser.Controller.Collections
public interface ICollectionManager
{
/// <summary>
+ /// Occurs when [collection created].
+ /// </summary>
+ event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
+
+ /// <summary>
+ /// Occurs when [items added to collection].
+ /// </summary>
+ event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
+
+ /// <summary>
+ /// Occurs when [items removed from collection].
+ /// </summary>
+ event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
+
+ /// <summary>
/// Creates the collection.
/// </summary>
/// <param name="options">The options.</param>
diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs
index 0d0555dc0..434e896da 100644
--- a/MediaBrowser.Controller/Dto/IDtoService.cs
+++ b/MediaBrowser.Controller/Dto/IDtoService.cs
@@ -51,6 +51,13 @@ namespace MediaBrowser.Controller.Dto
ChapterInfoDto GetChapterInfoDto(ChapterInfo chapterInfo, BaseItem item);
/// <summary>
+ /// Gets the user item data dto.
+ /// </summary>
+ /// <param name="data">The data.</param>
+ /// <returns>UserItemDataDto.</returns>
+ UserItemDataDto GetUserItemDataDto(UserItemData data);
+
+ /// <summary>
/// Gets the item by name dto.
/// </summary>
/// <param name="item">The item.</param>
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 4ad3033f9..1c60ea8e6 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -95,6 +95,7 @@
<Compile Include="Chapters\IChapterProvider.cs" />
<Compile Include="Chapters\ChapterResponse.cs" />
<Compile Include="Collections\CollectionCreationOptions.cs" />
+ <Compile Include="Collections\CollectionEvents.cs" />
<Compile Include="Collections\ICollectionManager.cs" />
<Compile Include="Dlna\ControlRequest.cs" />
<Compile Include="Dlna\ControlResponse.cs" />
@@ -233,6 +234,9 @@
<Compile Include="Providers\IRemoteMetadataProvider.cs" />
<Compile Include="Providers\VideoContentType.cs" />
<Compile Include="RelatedMedia\IRelatedMediaProvider.cs" />
+ <Compile Include="Security\AuthenticationInfo.cs" />
+ <Compile Include="Security\AuthenticationInfoQuery.cs" />
+ <Compile Include="Security\IAuthenticationRepository.cs" />
<Compile Include="Security\IEncryptionManager.cs" />
<Compile Include="Subtitles\ISubtitleManager.cs" />
<Compile Include="Subtitles\ISubtitleProvider.cs" />
diff --git a/MediaBrowser.Controller/Providers/IMetadataProvider.cs b/MediaBrowser.Controller/Providers/IMetadataProvider.cs
index d33b2c9eb..52cd6fcea 100644
--- a/MediaBrowser.Controller/Providers/IMetadataProvider.cs
+++ b/MediaBrowser.Controller/Providers/IMetadataProvider.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Controller.Entities;
+using System.Collections.Generic;
namespace MediaBrowser.Controller.Providers
{
diff --git a/MediaBrowser.Controller/Security/AuthenticationInfo.cs b/MediaBrowser.Controller/Security/AuthenticationInfo.cs
new file mode 100644
index 000000000..dd5eec1f9
--- /dev/null
+++ b/MediaBrowser.Controller/Security/AuthenticationInfo.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace MediaBrowser.Controller.Security
+{
+ public class AuthenticationInfo
+ {
+ /// <summary>
+ /// Gets or sets the identifier.
+ /// </summary>
+ /// <value>The identifier.</value>
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the access token.
+ /// </summary>
+ /// <value>The access token.</value>
+ public string AccessToken { get; set; }
+
+ /// <summary>
+ /// Gets or sets the device identifier.
+ /// </summary>
+ /// <value>The device identifier.</value>
+ public string DeviceId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name of the application.
+ /// </summary>
+ /// <value>The name of the application.</value>
+ public string AppName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name of the device.
+ /// </summary>
+ /// <value>The name of the device.</value>
+ public string DeviceName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user identifier.
+ /// </summary>
+ /// <value>The user identifier.</value>
+ public string UserId { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is active.
+ /// </summary>
+ /// <value><c>true</c> if this instance is active; otherwise, <c>false</c>.</value>
+ public bool IsActive { get; set; }
+
+ /// <summary>
+ /// Gets or sets the date created.
+ /// </summary>
+ /// <value>The date created.</value>
+ public DateTime DateCreated { get; set; }
+
+ /// <summary>
+ /// Gets or sets the date revoked.
+ /// </summary>
+ /// <value>The date revoked.</value>
+ public DateTime? DateRevoked { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs b/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs
new file mode 100644
index 000000000..3234b0350
--- /dev/null
+++ b/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs
@@ -0,0 +1,42 @@
+
+namespace MediaBrowser.Controller.Security
+{
+ public class AuthenticationInfoQuery
+ {
+ /// <summary>
+ /// Gets or sets the device identifier.
+ /// </summary>
+ /// <value>The device identifier.</value>
+ public string DeviceId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user identifier.
+ /// </summary>
+ /// <value>The user identifier.</value>
+ public string UserId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the access token.
+ /// </summary>
+ /// <value>The access token.</value>
+ public string AccessToken { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is active.
+ /// </summary>
+ /// <value><c>null</c> if [is active] contains no value, <c>true</c> if [is active]; otherwise, <c>false</c>.</value>
+ public bool? IsActive { get; set; }
+
+ /// <summary>
+ /// Gets or sets the start index.
+ /// </summary>
+ /// <value>The start index.</value>
+ public int? StartIndex { get; set; }
+
+ /// <summary>
+ /// Gets or sets the limit.
+ /// </summary>
+ /// <value>The limit.</value>
+ public int? Limit { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs
new file mode 100644
index 000000000..219b07028
--- /dev/null
+++ b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs
@@ -0,0 +1,39 @@
+using MediaBrowser.Model.Querying;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Security
+{
+ public interface IAuthenticationRepository
+ {
+ /// <summary>
+ /// Creates the specified information.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task Create(AuthenticationInfo info, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Updates the specified information.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task Update(AuthenticationInfo info, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the specified query.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>QueryResult{AuthenticationInfo}.</returns>
+ QueryResult<AuthenticationInfo> Get(AuthenticationInfoQuery query);
+
+ /// <summary>
+ /// Gets the specified identifier.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <returns>AuthenticationInfo.</returns>
+ AuthenticationInfo Get(string id);
+ }
+}
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index 7b2062182..4b30c964c 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -259,7 +259,28 @@ namespace MediaBrowser.Controller.Session
/// <summary>
/// Validates the security token.
/// </summary>
- /// <param name="token">The token.</param>
- void ValidateSecurityToken(string token);
+ /// <param name="accessToken">The access token.</param>
+ void ValidateSecurityToken(string accessToken);
+
+ /// <summary>
+ /// Logouts the specified access token.
+ /// </summary>
+ /// <param name="accessToken">The access token.</param>
+ /// <returns>Task.</returns>
+ Task Logout(string accessToken);
+
+ /// <summary>
+ /// Revokes the user tokens.
+ /// </summary>
+ /// <param name="userId">The user identifier.</param>
+ /// <returns>Task.</returns>
+ Task RevokeUserTokens(string userId);
+
+ /// <summary>
+ /// Determines whether the specified remote endpoint is local.
+ /// </summary>
+ /// <param name="remoteEndpoint">The remote endpoint.</param>
+ /// <returns><c>true</c> if the specified remote endpoint is local; otherwise, <c>false</c>.</returns>
+ bool IsLocal(string remoteEndpoint);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs
index 6f27f6cb2..58d455955 100644
--- a/MediaBrowser.Controller/Session/SessionInfo.cs
+++ b/MediaBrowser.Controller/Session/SessionInfo.cs
@@ -123,7 +123,7 @@ namespace MediaBrowser.Controller.Session
public List<string> SupportedCommands { get; set; }
public TranscodingInfo TranscodingInfo { get; set; }
-
+
/// <summary>
/// Gets a value indicating whether this instance is active.
/// </summary>
diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
index cc9bc7bed..62aec5ecb 100644
--- a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
@@ -1,11 +1,11 @@
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging;
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
namespace MediaBrowser.LocalMetadata
{
diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs
index 33c6f980c..74a3314b7 100644
--- a/MediaBrowser.Model/ApiClient/IApiClient.cs
+++ b/MediaBrowser.Model/ApiClient/IApiClient.cs
@@ -246,7 +246,7 @@ namespace MediaBrowser.Model.ApiClient
/// Gets the client session asynchronous.
/// </summary>
/// <returns>Task{SessionInfoDto}.</returns>
- Task<SessionInfoDto> GetCurrentSessionAsync();
+ Task<SessionInfoDto> GetCurrentSessionAsync(CancellationToken cancellationToken);
/// <summary>
/// Gets the item counts async.
@@ -645,6 +645,13 @@ namespace MediaBrowser.Model.ApiClient
Task SetVolume(string sessionId, int volume);
/// <summary>
+ /// Stops the transcoding processes.
+ /// </summary>
+ /// <param name="deviceId">The device identifier.</param>
+ /// <returns>Task.</returns>
+ Task StopTranscodingProcesses(string deviceId);
+
+ /// <summary>
/// Sets the index of the audio stream.
/// </summary>
/// <param name="sessionId">The session identifier.</param>
@@ -984,7 +991,7 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="query">The query.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{LiveTvInfo}.</returns>
- Task<QueryResult<ChannelInfoDto>> GetLiveTvChannelsAsync(ChannelQuery query, CancellationToken cancellationToken);
+ Task<QueryResult<ChannelInfoDto>> GetLiveTvChannelsAsync(LiveTvChannelQuery query, CancellationToken cancellationToken);
/// <summary>
/// Gets the live tv channel asynchronous.
@@ -1187,5 +1194,13 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{QueryResult{BaseItemDto}}.</returns>
Task<QueryResult<BaseItemDto>> GetChannels(ChannelQuery query, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the latest channel items.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{QueryResult{BaseItemDto}}.</returns>
+ Task<QueryResult<BaseItemDto>> GetLatestChannelItems(AllChannelMediaQuery query, CancellationToken cancellationToken);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 49b731341..d9404ce29 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -210,6 +210,8 @@ namespace MediaBrowser.Model.Configuration
public bool DefaultMetadataSettingsApplied { get; set; }
+ public bool EnableTokenAuthentication { get; set; }
+
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
/// </summary>
diff --git a/MediaBrowser.Model/Users/AuthenticationResult.cs b/MediaBrowser.Model/Users/AuthenticationResult.cs
index 8046e83c7..97fe2ea99 100644
--- a/MediaBrowser.Model/Users/AuthenticationResult.cs
+++ b/MediaBrowser.Model/Users/AuthenticationResult.cs
@@ -21,6 +21,6 @@ namespace MediaBrowser.Model.Users
/// Gets or sets the authentication token.
/// </summary>
/// <value>The authentication token.</value>
- public string AuthenticationToken { get; set; }
+ public string AccessToken { get; set; }
}
}
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index 95eca6ba0..7feca2d34 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -8,7 +8,6 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs
index 2783fda6b..f09890c40 100644
--- a/MediaBrowser.Providers/Manager/ProviderUtils.cs
+++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs
@@ -170,7 +170,7 @@ namespace MediaBrowser.Providers.Manager
var key = id.Key;
// Don't replace existing Id's.
- if (!target.ProviderIds.ContainsKey(key))
+ if (replaceData || !target.ProviderIds.ContainsKey(key))
{
target.ProviderIds[key] = id.Value;
}
diff --git a/MediaBrowser.Providers/TV/MovieDbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/MovieDbEpisodeImageProvider.cs
index 7979711ec..b3f62005b 100644
--- a/MediaBrowser.Providers/TV/MovieDbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/MovieDbEpisodeImageProvider.cs
@@ -19,7 +19,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Providers.TV
{
- public class MovieDbEpisodeImageProvider : IRemoteImageProvider, IHasOrder
+ public class MovieDbEpisodeImageProvider/* : IRemoteImageProvider, IHasOrder*/
{
private const string GetTvInfo3 = @"http://api.themoviedb.org/3/tv/{0}/season/{1}/episode/{2}?api_key={3}&append_to_response=images,external_ids,credits,videos";
private readonly IHttpClient _httpClient;
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index c6dd80758..d0ea64e0f 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -1133,6 +1133,8 @@ namespace MediaBrowser.Server.Implementations.Channels
item.CommunityRating = info.CommunityRating;
item.OfficialRating = info.OfficialRating;
item.Overview = info.Overview;
+ item.IndexNumber = info.IndexNumber;
+ item.ParentIndexNumber = info.ParentIndexNumber;
item.People = info.People;
item.PremiereDate = info.PremiereDate;
item.ProductionYear = info.ProductionYear;
@@ -1159,7 +1161,6 @@ namespace MediaBrowser.Server.Implementations.Channels
if (channelMediaItem != null)
{
- channelMediaItem.IsInfiniteStream = info.IsInfiniteStream;
channelMediaItem.ContentType = info.ContentType;
channelMediaItem.ChannelMediaSources = info.MediaSources;
diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
index 728b18bbf..7bc7838c6 100644
--- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
+++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
@@ -1,9 +1,11 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Events;
+using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Logging;
using MoreLinq;
using System;
using System.Collections.Generic;
@@ -19,12 +21,18 @@ namespace MediaBrowser.Server.Implementations.Collections
private readonly ILibraryManager _libraryManager;
private readonly IFileSystem _fileSystem;
private readonly ILibraryMonitor _iLibraryMonitor;
+ private readonly ILogger _logger;
- public CollectionManager(ILibraryManager libraryManager, IFileSystem fileSystem, ILibraryMonitor iLibraryMonitor)
+ public event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
+ public event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
+ public event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
+
+ public CollectionManager(ILibraryManager libraryManager, IFileSystem fileSystem, ILibraryMonitor iLibraryMonitor, ILogger logger)
{
_libraryManager = libraryManager;
_fileSystem = fileSystem;
_iLibraryMonitor = iLibraryMonitor;
+ _logger = logger;
}
public Folder GetCollectionsFolder(string userId)
@@ -74,9 +82,16 @@ namespace MediaBrowser.Server.Implementations.Collections
if (options.ItemIdList.Count > 0)
{
- await AddToCollection(collection.Id, options.ItemIdList);
+ await AddToCollection(collection.Id, options.ItemIdList, false);
}
+ EventHelper.FireEventIfNotNull(CollectionCreated, this, new CollectionCreatedEventArgs
+ {
+ Collection = collection,
+ Options = options
+
+ }, _logger);
+
return collection;
}
finally
@@ -113,7 +128,12 @@ namespace MediaBrowser.Server.Implementations.Collections
return GetCollectionsFolder(string.Empty);
}
- public async Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
+ public Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
+ {
+ return AddToCollection(collectionId, ids, true);
+ }
+
+ private async Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent)
{
var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
@@ -123,6 +143,7 @@ namespace MediaBrowser.Server.Implementations.Collections
}
var list = new List<LinkedChild>();
+ var itemList = new List<BaseItem>();
var currentLinkedChildren = collection.GetLinkedChildren().ToList();
foreach (var itemId in ids)
@@ -134,6 +155,8 @@ namespace MediaBrowser.Server.Implementations.Collections
throw new ArgumentException("No item exists with the supplied Id");
}
+ itemList.Add(item);
+
if (currentLinkedChildren.Any(i => i.Id == itemId))
{
throw new ArgumentException("Item already exists in collection");
@@ -165,6 +188,16 @@ namespace MediaBrowser.Server.Implementations.Collections
await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
+
+ if (fireEvent)
+ {
+ EventHelper.FireEventIfNotNull(ItemsRemovedFromCollection, this, new CollectionModifiedEventArgs
+ {
+ Collection = collection,
+ ItemsChanged = itemList
+
+ }, _logger);
+ }
}
public async Task RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds)
@@ -177,6 +210,7 @@ namespace MediaBrowser.Server.Implementations.Collections
}
var list = new List<LinkedChild>();
+ var itemList = new List<BaseItem>();
foreach (var itemId in itemIds)
{
@@ -190,6 +224,12 @@ namespace MediaBrowser.Server.Implementations.Collections
list.Add(child);
var childItem = _libraryManager.GetItemById(itemId);
+
+ if (childItem != null)
+ {
+ itemList.Add(childItem);
+ }
+
var supportsGrouping = childItem as ISupportsBoxSetGrouping;
if (supportsGrouping != null)
@@ -221,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.Collections
{
File.Delete(file);
}
-
+
foreach (var child in list)
{
collection.LinkedChildren.Remove(child);
@@ -238,6 +278,13 @@ namespace MediaBrowser.Server.Implementations.Collections
await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
+
+ EventHelper.FireEventIfNotNull(ItemsRemovedFromCollection, this, new CollectionModifiedEventArgs
+ {
+ Collection = collection,
+ ItemsChanged = itemList
+
+ }, _logger);
}
public IEnumerable<BaseItem> CollapseItemsWithinBoxSets(IEnumerable<BaseItem> items, User user)
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
index c29a7d14e..6894d7ac7 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
@@ -1,4 +1,4 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
@@ -13,9 +13,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
{
public class AuthService : IAuthService
{
- public AuthService(IUserManager userManager, ISessionManager sessionManager, IAuthorizationContext authorizationContext)
+ private readonly IServerConfigurationManager _config;
+
+ public AuthService(IUserManager userManager, ISessionManager sessionManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config)
{
AuthorizationContext = authorizationContext;
+ _config = config;
SessionManager = sessionManager;
UserManager = userManager;
}
@@ -54,28 +57,30 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
//This code is executed before the service
var auth = AuthorizationContext.GetAuthorizationInfo(req);
- if (string.IsNullOrWhiteSpace(auth.Token))
+ if (!string.IsNullOrWhiteSpace(auth.Token) || _config.Configuration.EnableTokenAuthentication)
{
- // Legacy
- // TODO: Deprecate this in Oct 2014
-
- User user = null;
-
- if (!string.IsNullOrWhiteSpace(auth.UserId))
- {
- var userId = auth.UserId;
+ SessionManager.ValidateSecurityToken(auth.Token);
+ }
- user = UserManager.GetUserById(new Guid(userId));
- }
+ var user = string.IsNullOrWhiteSpace(auth.UserId)
+ ? null
+ : UserManager.GetUserById(new Guid(auth.UserId));
- if (user == null || user.Configuration.IsDisabled)
- {
- throw new UnauthorizedAccessException("Unauthorized access.");
- }
+ if (user != null && user.Configuration.IsDisabled)
+ {
+ throw new UnauthorizedAccessException("User account has been disabled.");
}
- else
+
+ if (!string.IsNullOrWhiteSpace(auth.DeviceId) &&
+ !string.IsNullOrWhiteSpace(auth.Client) &&
+ !string.IsNullOrWhiteSpace(auth.Device))
{
- SessionManager.ValidateSecurityToken(auth.Token);
+ SessionManager.LogSessionActivity(auth.Client,
+ auth.Version,
+ auth.DeviceId,
+ auth.Device,
+ req.RemoteIp,
+ user);
}
}
@@ -108,11 +113,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
}
}
- private void LogRequest()
- {
-
- }
-
protected bool DoHtmlRedirectIfConfigured(IRequest req, IResponse res, bool includeRedirectParam = false)
{
var htmlRedirect = this.HtmlRedirect ?? AuthenticateService.HtmlRedirect;
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 1d201e069..859011f6e 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -216,6 +216,7 @@
<Compile Include="ScheduledTasks\ChapterImagesTask.cs" />
<Compile Include="ScheduledTasks\RefreshIntrosTask.cs" />
<Compile Include="ScheduledTasks\RefreshMediaLibraryTask.cs" />
+ <Compile Include="Security\AuthenticationRepository.cs" />
<Compile Include="Security\EncryptionManager.cs" />
<Compile Include="ServerApplicationPaths.cs" />
<Compile Include="ServerManager\ServerManager.cs" />
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
index df32ac021..5d5855bf8 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
@@ -14,7 +14,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.Persistence
{
- public class SqliteFileOrganizationRepository : IFileOrganizationRepository
+ public class SqliteFileOrganizationRepository : IFileOrganizationRepository, IDisposable
{
private IDbConnection _connection;
diff --git a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
new file mode 100644
index 000000000..5f225ddd4
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
@@ -0,0 +1,338 @@
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Security;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Querying;
+using MediaBrowser.Server.Implementations.Persistence;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Globalization;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Security
+{
+ public class AuthenticationRepository : IAuthenticationRepository
+ {
+ private IDbConnection _connection;
+ private readonly ILogger _logger;
+ private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
+ private readonly IServerApplicationPaths _appPaths;
+ private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+
+ private IDbCommand _saveInfoCommand;
+
+ public AuthenticationRepository(ILogger logger, IServerApplicationPaths appPaths)
+ {
+ _logger = logger;
+ _appPaths = appPaths;
+ }
+
+ public async Task Initialize()
+ {
+ var dbFile = Path.Combine(_appPaths.DataPath, "authentication.db");
+
+ _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
+
+ string[] queries = {
+
+ "create table if not exists AccessTokens (Id GUID PRIMARY KEY, AccessToken TEXT NOT NULL, DeviceId TEXT, AppName TEXT, DeviceName TEXT, UserId TEXT, IsActive BIT, DateCreated DATETIME NOT NULL, DateRevoked DATETIME)",
+ "create index if not exists idx_AccessTokens on AccessTokens(Id)",
+
+ //pragmas
+ "pragma temp_store = memory",
+
+ "pragma shrink_memory"
+ };
+
+ _connection.RunQueries(queries, _logger);
+
+ PrepareStatements();
+ }
+
+ private void PrepareStatements()
+ {
+ _saveInfoCommand = _connection.CreateCommand();
+ _saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)";
+
+ _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@Id");
+ _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AccessToken");
+ _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DeviceId");
+ _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AppName");
+ _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DeviceName");
+ _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@UserId");
+ _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@IsActive");
+ _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DateCreated");
+ _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DateRevoked");
+ }
+
+ public Task Create(AuthenticationInfo info, CancellationToken cancellationToken)
+ {
+ info.Id = Guid.NewGuid().ToString("N");
+
+ return Update(info, cancellationToken);
+ }
+
+ public async Task Update(AuthenticationInfo info, CancellationToken cancellationToken)
+ {
+ if (info == null)
+ {
+ throw new ArgumentNullException("info");
+ }
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = _connection.BeginTransaction();
+
+ var index = 0;
+
+ _saveInfoCommand.GetParameter(index++).Value = new Guid(info.Id);
+ _saveInfoCommand.GetParameter(index++).Value = info.AccessToken;
+ _saveInfoCommand.GetParameter(index++).Value = info.DeviceId;
+ _saveInfoCommand.GetParameter(index++).Value = info.AppName;
+ _saveInfoCommand.GetParameter(index++).Value = info.DeviceName;
+ _saveInfoCommand.GetParameter(index++).Value = info.UserId;
+ _saveInfoCommand.GetParameter(index++).Value = info.IsActive;
+ _saveInfoCommand.GetParameter(index++).Value = info.DateCreated;
+ _saveInfoCommand.GetParameter(index++).Value = info.DateRevoked;
+
+ _saveInfoCommand.Transaction = transaction;
+
+ _saveInfoCommand.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ catch (Exception e)
+ {
+ _logger.ErrorException("Failed to save record:", e);
+
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+
+ _writeLock.Release();
+ }
+ }
+
+ private const string BaseSelectText = "select Id, AccessToken, DeviceId, AppName, DeviceName, UserId, IsActive, DateCreated, DateRevoked from AccessTokens";
+
+ public QueryResult<AuthenticationInfo> Get(AuthenticationInfoQuery query)
+ {
+ if (query == null)
+ {
+ throw new ArgumentNullException("query");
+ }
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = BaseSelectText;
+
+ var whereClauses = new List<string>();
+
+ var startIndex = query.StartIndex ?? 0;
+
+ if (startIndex > 0)
+ {
+ whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens ORDER BY DateCreated LIMIT {0})",
+ startIndex.ToString(_usCulture)));
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.AccessToken))
+ {
+ whereClauses.Add("AccessToken=@AccessToken");
+ cmd.Parameters.Add(cmd, "@AccessToken", DbType.String).Value = query.AccessToken;
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.UserId))
+ {
+ whereClauses.Add("UserId=@UserId");
+ cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId;
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.DeviceId))
+ {
+ whereClauses.Add("DeviceId=@DeviceId");
+ cmd.Parameters.Add(cmd, "@DeviceId", DbType.String).Value = query.DeviceId;
+ }
+
+ if (query.IsActive.HasValue)
+ {
+ whereClauses.Add("IsActive=@IsActive");
+ cmd.Parameters.Add(cmd, "@IsActive", DbType.Boolean).Value = query.IsActive.Value;
+ }
+
+ if (whereClauses.Count > 0)
+ {
+ cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray());
+ }
+
+ cmd.CommandText += " ORDER BY DateCreated";
+
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
+ }
+
+ cmd.CommandText += "; select count (Id) from AccessTokens";
+
+ var list = new List<AuthenticationInfo>();
+ var count = 0;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
+ {
+ while (reader.Read())
+ {
+ list.Add(Get(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
+ }
+
+ return new QueryResult<AuthenticationInfo>()
+ {
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
+ }
+ }
+
+ public AuthenticationInfo Get(string id)
+ {
+ if (string.IsNullOrEmpty(id))
+ {
+ throw new ArgumentNullException("id");
+ }
+
+ var guid = new Guid(id);
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = BaseSelectText + " where Id=@Id";
+
+ cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+ {
+ if (reader.Read())
+ {
+ return Get(reader);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private AuthenticationInfo Get(IDataReader reader)
+ {
+ var s = "select Id, AccessToken, DeviceId, AppName, DeviceName, UserId, IsActive, DateCreated, DateRevoked from AccessTokens";
+
+ var info = new AuthenticationInfo
+ {
+ Id = reader.GetGuid(0).ToString("N"),
+ AccessToken = reader.GetString(1)
+ };
+
+ if (!reader.IsDBNull(2))
+ {
+ info.DeviceId = reader.GetString(2);
+ }
+
+ if (!reader.IsDBNull(3))
+ {
+ info.AppName = reader.GetString(3);
+ }
+
+ if (!reader.IsDBNull(4))
+ {
+ info.DeviceName = reader.GetString(4);
+ }
+
+ if (!reader.IsDBNull(5))
+ {
+ info.UserId = reader.GetString(5);
+ }
+
+ info.IsActive = reader.GetBoolean(6);
+ info.DateCreated = reader.GetDateTime(7);
+
+ if (!reader.IsDBNull(8))
+ {
+ info.DateRevoked = reader.GetDateTime(8);
+ }
+
+ return info;
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private readonly object _disposeLock = new object();
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool dispose)
+ {
+ if (dispose)
+ {
+ try
+ {
+ lock (_disposeLock)
+ {
+ if (_connection != null)
+ {
+ if (_connection.IsOpen())
+ {
+ _connection.Close();
+ }
+
+ _connection.Dispose();
+ _connection = null;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error disposing database", ex);
+ }
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 784719318..c3d24c0de 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -1,6 +1,4 @@
-using System.Security.Cryptography;
-using System.Text;
-using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
@@ -13,12 +11,14 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Session;
+using MediaBrowser.Model.Users;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -27,7 +27,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Users;
namespace MediaBrowser.Server.Implementations.Session
{
@@ -62,6 +61,8 @@ namespace MediaBrowser.Server.Implementations.Session
private readonly IJsonSerializer _jsonSerializer;
private readonly IServerApplicationHost _appHost;
+ private readonly IAuthenticationRepository _authRepo;
+
/// <summary>
/// Gets or sets the configuration manager.
/// </summary>
@@ -104,7 +105,7 @@ namespace MediaBrowser.Server.Implementations.Session
/// <param name="logger">The logger.</param>
/// <param name="userRepository">The user repository.</param>
/// <param name="libraryManager">The library manager.</param>
- public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient)
+ public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo)
{
_userDataRepository = userDataRepository;
_configurationManager = configurationManager;
@@ -119,6 +120,7 @@ namespace MediaBrowser.Server.Implementations.Session
_jsonSerializer = jsonSerializer;
_appHost = appHost;
_httpClient = httpClient;
+ _authRepo = authRepo;
}
/// <summary>
@@ -204,7 +206,12 @@ namespace MediaBrowser.Server.Implementations.Session
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">user</exception>
/// <exception cref="System.UnauthorizedAccessException"></exception>
- public async Task<SessionInfo> LogSessionActivity(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user)
+ public async Task<SessionInfo> LogSessionActivity(string clientType,
+ string appVersion,
+ string deviceId,
+ string deviceName,
+ string remoteEndPoint,
+ User user)
{
if (string.IsNullOrEmpty(clientType))
{
@@ -1157,7 +1164,37 @@ namespace MediaBrowser.Server.Implementations.Session
public void ValidateSecurityToken(string token)
{
+ if (string.IsNullOrWhiteSpace(token))
+ {
+ throw new UnauthorizedAccessException();
+ }
+ var result = _authRepo.Get(new AuthenticationInfoQuery
+ {
+ AccessToken = token
+ });
+
+ var info = result.Items.FirstOrDefault();
+
+ if (info == null)
+ {
+ throw new UnauthorizedAccessException();
+ }
+
+ if (!info.IsActive)
+ {
+ throw new UnauthorizedAccessException("Access token has expired.");
+ }
+
+ if (!string.IsNullOrWhiteSpace(info.UserId))
+ {
+ var user = _userManager.GetUserById(new Guid(info.UserId));
+
+ if (user == null || user.Configuration.IsDisabled)
+ {
+ throw new UnauthorizedAccessException("User account has been disabled.");
+ }
+ }
}
/// <summary>
@@ -1175,7 +1212,7 @@ namespace MediaBrowser.Server.Implementations.Session
/// <exception cref="UnauthorizedAccessException"></exception>
public async Task<AuthenticationResult> AuthenticateNewSession(string username, string password, string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint)
{
- var result = await _userManager.AuthenticateUser(username, password).ConfigureAwait(false);
+ var result = IsLocalhost(remoteEndPoint) || await _userManager.AuthenticateUser(username, password).ConfigureAwait(false);
if (!result)
{
@@ -1185,6 +1222,8 @@ namespace MediaBrowser.Server.Implementations.Session
var user = _userManager.Users
.First(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
+ var token = await GetAuthorizationToken(user.Id.ToString("N"), deviceId, clientType, deviceName).ConfigureAwait(false);
+
var session = await LogSessionActivity(clientType,
appVersion,
deviceId,
@@ -1197,11 +1236,108 @@ namespace MediaBrowser.Server.Implementations.Session
{
User = _dtoService.GetUserDto(user),
SessionInfo = GetSessionInfoDto(session),
- AuthenticationToken = Guid.NewGuid().ToString("N")
+ AccessToken = token
};
}
- private bool IsLocal(string remoteEndpoint)
+ private async Task<string> GetAuthorizationToken(string userId, string deviceId, string app, string deviceName)
+ {
+ var existing = _authRepo.Get(new AuthenticationInfoQuery
+ {
+ DeviceId = deviceId,
+ IsActive = true,
+ UserId = userId,
+ Limit = 1
+ });
+
+ if (existing.Items.Length > 0)
+ {
+ _logger.Debug("Reissuing access token");
+ return existing.Items[0].AccessToken;
+ }
+
+ var newToken = new AuthenticationInfo
+ {
+ AppName = app,
+ DateCreated = DateTime.UtcNow,
+ DeviceId = deviceId,
+ DeviceName = deviceName,
+ UserId = userId,
+ IsActive = true,
+ AccessToken = Guid.NewGuid().ToString("N")
+ };
+
+ _logger.Debug("Creating new access token for user {0}", userId);
+ await _authRepo.Create(newToken, CancellationToken.None).ConfigureAwait(false);
+
+ return newToken.AccessToken;
+ }
+
+ public async Task Logout(string accessToken)
+ {
+ if (string.IsNullOrWhiteSpace(accessToken))
+ {
+ throw new ArgumentNullException("accessToken");
+ }
+
+ var existing = _authRepo.Get(new AuthenticationInfoQuery
+ {
+ Limit = 1,
+ AccessToken = accessToken
+
+ }).Items.FirstOrDefault();
+
+ if (existing != null)
+ {
+ existing.IsActive = false;
+
+ await _authRepo.Update(existing, CancellationToken.None).ConfigureAwait(false);
+
+ var sessions = Sessions
+ .Where(i => string.Equals(i.DeviceId, existing.DeviceId, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ foreach (var session in sessions)
+ {
+ try
+ {
+ ReportSessionEnded(session.Id);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error reporting session ended", ex);
+ }
+ }
+ }
+ }
+
+ public async Task RevokeUserTokens(string userId)
+ {
+ var existing = _authRepo.Get(new AuthenticationInfoQuery
+ {
+ IsActive = true,
+ UserId = userId
+ });
+
+ foreach (var info in existing.Items)
+ {
+ await Logout(info.AccessToken).ConfigureAwait(false);
+ }
+ }
+
+ private bool IsLocalhost(string remoteEndpoint)
+ {
+ if (string.IsNullOrWhiteSpace(remoteEndpoint))
+ {
+ throw new ArgumentNullException("remoteEndpoint");
+ }
+
+ return remoteEndpoint.IndexOf("localhost", StringComparison.OrdinalIgnoreCase) != -1 ||
+ remoteEndpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
+ remoteEndpoint.StartsWith("::", StringComparison.OrdinalIgnoreCase);
+ }
+
+ public bool IsLocal(string remoteEndpoint)
{
if (string.IsNullOrWhiteSpace(remoteEndpoint))
{
@@ -1211,12 +1347,11 @@ namespace MediaBrowser.Server.Implementations.Session
// Private address space:
// http://en.wikipedia.org/wiki/Private_network
- return remoteEndpoint.IndexOf("localhost", StringComparison.OrdinalIgnoreCase) != -1 ||
+ return IsLocalhost(remoteEndpoint) ||
remoteEndpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
remoteEndpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) ||
remoteEndpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) ||
- remoteEndpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
- remoteEndpoint.StartsWith("::", StringComparison.OrdinalIgnoreCase);
+ remoteEndpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 91e92e21c..ca04e580f 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -210,6 +210,8 @@ namespace MediaBrowser.ServerApplication
private IUserViewManager UserViewManager { get; set; }
+ private IAuthenticationRepository AuthenticationRepository { get; set; }
+
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationHost"/> class.
/// </summary>
@@ -586,6 +588,9 @@ namespace MediaBrowser.ServerApplication
FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false);
RegisterSingleInstance(FileOrganizationRepository);
+ AuthenticationRepository = await GetAuthenticationRepository().ConfigureAwait(false);
+ RegisterSingleInstance(AuthenticationRepository);
+
UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer);
RegisterSingleInstance(UserManager);
@@ -625,7 +630,7 @@ namespace MediaBrowser.ServerApplication
DtoService = new DtoService(Logger, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager);
RegisterSingleInstance(DtoService);
- SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient);
+ SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient, AuthenticationRepository);
RegisterSingleInstance(SessionManager);
var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
@@ -651,7 +656,7 @@ namespace MediaBrowser.ServerApplication
var connectionManager = new ConnectionManager(dlnaManager, ServerConfigurationManager, LogManager.GetLogger("UpnpConnectionManager"), HttpClient);
RegisterSingleInstance<IConnectionManager>(connectionManager);
- var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor);
+ var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager"));
RegisterSingleInstance<ICollectionManager>(collectionManager);
LiveTvManager = new LiveTvManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager);
@@ -678,7 +683,7 @@ namespace MediaBrowser.ServerApplication
var authContext = new AuthorizationContext();
RegisterSingleInstance<IAuthorizationContext>(authContext);
RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
- RegisterSingleInstance<IAuthService>(new AuthService(UserManager, SessionManager, authContext));
+ RegisterSingleInstance<IAuthService>(new AuthService(UserManager, SessionManager, authContext, ServerConfigurationManager));
RegisterSingleInstance<ISubtitleEncoder>(new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder));
@@ -755,6 +760,15 @@ namespace MediaBrowser.ServerApplication
return repo;
}
+ private async Task<IAuthenticationRepository> GetAuthenticationRepository()
+ {
+ var repo = new AuthenticationRepository(LogManager.GetLogger("AuthenticationRepository"), ServerConfigurationManager.ApplicationPaths);
+
+ await repo.Initialize().ConfigureAwait(false);
+
+ return repo;
+ }
+
/// <summary>
/// Configures the repositories.
/// </summary>
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index 0515148f0..49851f42a 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -77,7 +77,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
/// <param name="cancellationToken">The cancellation token.</param>
private void Fetch(T item, string metadataFile, XmlReaderSettings settings, Encoding encoding, CancellationToken cancellationToken)
{
- using (var streamReader = new StreamReader(metadataFile, encoding))
+ using (var streamReader = new StreamReader(metadataFile))
{
// Use XmlReader for best performance
using (var reader = XmlReader.Create(streamReader, settings))
diff --git a/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs
index 65648e1d0..47371ea04 100644
--- a/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs
@@ -27,7 +27,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
var path = file.FullName;
- await XmlProviderUtils.XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+ //await XmlProviderUtils.XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
@@ -44,10 +44,10 @@ namespace MediaBrowser.XbmcMetadata.Providers
{
result.HasMetadata = false;
}
- finally
- {
- XmlProviderUtils.XmlParsingResourcePool.Release();
- }
+ //finally
+ //{
+ // XmlProviderUtils.XmlParsingResourcePool.Release();
+ //}
return result;
}
diff --git a/MediaBrowser.XbmcMetadata/Savers/SeasonXmlSaver.cs b/MediaBrowser.XbmcMetadata/Savers/SeasonXmlSaver.cs
index 1b6c7a340..a96b0636f 100644
--- a/MediaBrowser.XbmcMetadata/Savers/SeasonXmlSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/SeasonXmlSaver.cs
@@ -1,15 +1,14 @@
-using System.Collections.Generic;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Security;
using System.Text;
using System.Threading;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
namespace MediaBrowser.XbmcMetadata.Savers
{
diff --git a/MediaBrowser.XbmcMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.XbmcMetadata/Savers/XmlSaverHelpers.cs
index 7f817f591..7111a429a 100644
--- a/MediaBrowser.XbmcMetadata/Savers/XmlSaverHelpers.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/XmlSaverHelpers.cs
@@ -1,12 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Security;
-using System.Text;
-using System.Xml;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@@ -18,6 +10,14 @@ using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.XbmcMetadata.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Security;
+using System.Text;
+using System.Xml;
namespace MediaBrowser.XbmcMetadata.Savers
{
@@ -392,9 +392,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
builder.Append("<writer>" + SecurityElement.Escape(person) + "</writer>");
}
- if (writers.Count > 0)
+ foreach (var person in writers)
{
- builder.Append("<credits>" + SecurityElement.Escape(string.Join(" / ", writers.ToArray())) + "</credits>");
+ builder.Append("<credits>" + SecurityElement.Escape(person) + "</credits>");
}
var hasTrailer = item as IHasTrailers;
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index 8c83ffabc..f9e8c5aad 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
- <version>3.0.412</version>
+ <version>3.0.414</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.412" />
+ <dependency id="MediaBrowser.Common" version="3.0.414" />
<dependency id="NLog" version="2.1.0" />
<dependency id="SimpleInjector" version="2.5.0" />
<dependency id="sharpcompress" version="0.10.2" />
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 88431b72c..89aeff0a3 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
- <version>3.0.412</version>
+ <version>3.0.414</version>
<title>MediaBrowser.Common</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index 73f764fd5..1696ee347 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
- <version>3.0.412</version>
+ <version>3.0.414</version>
<title>Media Browser.Server.Core</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Media Browser Server.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.412" />
+ <dependency id="MediaBrowser.Common" version="3.0.414" />
</dependencies>
</metadata>
<files>