mirror of https://github.com/jellyfin/jellyfin.git
fixes #941 - Rework password recovery and remove IsLocal checks
This commit is contained in:
parent
0ef95fb19c
commit
40897bac14
|
@ -1,5 +1,4 @@
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Images
|
namespace MediaBrowser.Api.Images
|
||||||
|
@ -54,7 +53,7 @@ namespace MediaBrowser.Api.Images
|
||||||
public bool EnableImageEnhancers { get; set; }
|
public bool EnableImageEnhancers { get; set; }
|
||||||
|
|
||||||
[ApiMember(Name = "Format", Description = "Determines the output foramt of the image - original,gif,jpg,png", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "Format", Description = "Determines the output foramt of the image - original,gif,jpg,png", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||||
public ImageOutputFormat Format { get; set; }
|
public string Format { get; set; }
|
||||||
|
|
||||||
[ApiMember(Name = "AddPlayedIndicator", Description = "Optional. Add a played indicator", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "AddPlayedIndicator", Description = "Optional. Add a played indicator", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||||
public bool AddPlayedIndicator { get; set; }
|
public bool AddPlayedIndicator { get; set; }
|
||||||
|
@ -71,8 +70,6 @@ namespace MediaBrowser.Api.Images
|
||||||
public ImageRequest()
|
public ImageRequest()
|
||||||
{
|
{
|
||||||
EnableImageEnhancers = true;
|
EnableImageEnhancers = true;
|
||||||
|
|
||||||
Format = ImageOutputFormat.Original;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -542,7 +542,8 @@ namespace MediaBrowser.Api.Images
|
||||||
|
|
||||||
}).ToList() : new List<IImageEnhancer>();
|
}).ToList() : new List<IImageEnhancer>();
|
||||||
|
|
||||||
var contentType = GetMimeType(request.Format, imageInfo.Path);
|
var format = GetOutputFormat(request, imageInfo, supportedImageEnhancers);
|
||||||
|
var contentType = GetMimeType(format, imageInfo.Path);
|
||||||
|
|
||||||
var cacheGuid = new Guid(_imageProcessor.GetImageCacheTag(item, imageInfo, supportedImageEnhancers));
|
var cacheGuid = new Guid(_imageProcessor.GetImageCacheTag(item, imageInfo, supportedImageEnhancers));
|
||||||
|
|
||||||
|
@ -562,6 +563,7 @@ namespace MediaBrowser.Api.Images
|
||||||
return GetImageResult(item,
|
return GetImageResult(item,
|
||||||
request,
|
request,
|
||||||
imageInfo,
|
imageInfo,
|
||||||
|
format,
|
||||||
supportedImageEnhancers,
|
supportedImageEnhancers,
|
||||||
contentType,
|
contentType,
|
||||||
cacheDuration,
|
cacheDuration,
|
||||||
|
@ -573,6 +575,7 @@ namespace MediaBrowser.Api.Images
|
||||||
private async Task<object> GetImageResult(IHasImages item,
|
private async Task<object> GetImageResult(IHasImages item,
|
||||||
ImageRequest request,
|
ImageRequest request,
|
||||||
ItemImageInfo image,
|
ItemImageInfo image,
|
||||||
|
ImageOutputFormat format,
|
||||||
List<IImageEnhancer> enhancers,
|
List<IImageEnhancer> enhancers,
|
||||||
string contentType,
|
string contentType,
|
||||||
TimeSpan? cacheDuration,
|
TimeSpan? cacheDuration,
|
||||||
|
@ -598,11 +601,11 @@ namespace MediaBrowser.Api.Images
|
||||||
MaxWidth = request.MaxWidth,
|
MaxWidth = request.MaxWidth,
|
||||||
Quality = request.Quality,
|
Quality = request.Quality,
|
||||||
Width = request.Width,
|
Width = request.Width,
|
||||||
OutputFormat = request.Format,
|
|
||||||
AddPlayedIndicator = request.AddPlayedIndicator,
|
AddPlayedIndicator = request.AddPlayedIndicator,
|
||||||
PercentPlayed = request.PercentPlayed ?? 0,
|
PercentPlayed = request.PercentPlayed ?? 0,
|
||||||
UnplayedCount = request.UnplayedCount,
|
UnplayedCount = request.UnplayedCount,
|
||||||
BackgroundColor = request.BackgroundColor
|
BackgroundColor = request.BackgroundColor,
|
||||||
|
OutputFormat = format
|
||||||
};
|
};
|
||||||
|
|
||||||
var file = await _imageProcessor.ProcessImage(options).ConfigureAwait(false);
|
var file = await _imageProcessor.ProcessImage(options).ConfigureAwait(false);
|
||||||
|
@ -617,6 +620,52 @@ namespace MediaBrowser.Api.Images
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ImageOutputFormat GetOutputFormat(ImageRequest request, ItemImageInfo image, List<IImageEnhancer> enhancers)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.Format))
|
||||||
|
{
|
||||||
|
ImageOutputFormat format;
|
||||||
|
if (Enum.TryParse(request.Format, true, out format))
|
||||||
|
{
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var serverFormats = _imageProcessor.GetSupportedImageOutputFormats();
|
||||||
|
|
||||||
|
var clientFormats = GetClientSupportedFormats();
|
||||||
|
|
||||||
|
if (serverFormats.Contains(ImageOutputFormat.Webp) &&
|
||||||
|
clientFormats.Contains(ImageOutputFormat.Webp))
|
||||||
|
{
|
||||||
|
return ImageOutputFormat.Webp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enhancers.Count > 0)
|
||||||
|
{
|
||||||
|
return ImageOutputFormat.Png;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(Path.GetExtension(image.Path), ".jpg", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(Path.GetExtension(image.Path), ".jpeg", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return ImageOutputFormat.Jpg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't predict if there will be transparency or not, so play it safe
|
||||||
|
return ImageOutputFormat.Png;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageOutputFormat[] GetClientSupportedFormats()
|
||||||
|
{
|
||||||
|
if (Request.AcceptTypes.Contains("image/webp", StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return new[] { ImageOutputFormat.Webp, ImageOutputFormat.Jpg, ImageOutputFormat.Png };
|
||||||
|
}
|
||||||
|
|
||||||
|
return new[] { ImageOutputFormat.Jpg, ImageOutputFormat.Png };
|
||||||
|
}
|
||||||
|
|
||||||
private string GetMimeType(ImageOutputFormat format, string path)
|
private string GetMimeType(ImageOutputFormat format, string path)
|
||||||
{
|
{
|
||||||
if (format == ImageOutputFormat.Bmp)
|
if (format == ImageOutputFormat.Bmp)
|
||||||
|
|
|
@ -598,6 +598,8 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
|
var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
|
||||||
|
|
||||||
|
args += " -r 24 -g 24";
|
||||||
|
|
||||||
// Add resolution params, if specified
|
// Add resolution params, if specified
|
||||||
if (!hasGraphicalSubs)
|
if (!hasGraphicalSubs)
|
||||||
{
|
{
|
||||||
|
@ -615,6 +617,9 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
|
protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
|
||||||
{
|
{
|
||||||
|
// test url http://192.168.1.2:8096/mediabrowser/videos/233e8905d559a8f230db9bffd2ac9d6d/master.mpd?mediasourceid=233e8905d559a8f230db9bffd2ac9d6d&videocodec=h264&audiocodec=aac&maxwidth=1280&videobitrate=500000&audiobitrate=128000&profile=baseline&level=3
|
||||||
|
// Good info on i-frames http://blog.streamroot.io/encode-multi-bitrate-videos-mpeg-dash-mse-based-media-players/
|
||||||
|
|
||||||
var threads = GetNumberOfThreads(state, false);
|
var threads = GetNumberOfThreads(state, false);
|
||||||
|
|
||||||
var inputModifier = GetInputModifier(state);
|
var inputModifier = GetInputModifier(state);
|
||||||
|
@ -624,7 +629,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
var segmentFilename = Path.GetFileNameWithoutExtension(outputPath) + "%03d" + GetSegmentFileExtension(state);
|
var segmentFilename = Path.GetFileNameWithoutExtension(outputPath) + "%03d" + GetSegmentFileExtension(state);
|
||||||
|
|
||||||
var args = string.Format("{0} -i {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -f ssegment -segment_time {6} -segment_format_options movflags=+faststart -segment_list_size {8} -segment_list \"{9}\" {10}",
|
var args = string.Format("{0} -i {1} -map_metadata -1 -threads {2} {3} {4} -copyts {5} -f ssegment -segment_time {6} -segment_list_size {8} -segment_list \"{9}\" {10}",
|
||||||
inputModifier,
|
inputModifier,
|
||||||
GetInputArgument(transcodingJobId, state),
|
GetInputArgument(transcodingJobId, state),
|
||||||
threads,
|
threads,
|
||||||
|
|
|
@ -44,9 +44,10 @@ namespace MediaBrowser.Api.System
|
||||||
/// This is currently not authenticated because the uninstaller needs to be able to shutdown the server.
|
/// This is currently not authenticated because the uninstaller needs to be able to shutdown the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/System/Shutdown", "POST", Summary = "Shuts down the application")]
|
[Route("/System/Shutdown", "POST", Summary = "Shuts down the application")]
|
||||||
[Authenticated(AllowLocal = true)]
|
|
||||||
public class ShutdownApplication
|
public class ShutdownApplication
|
||||||
{
|
{
|
||||||
|
// TODO: This is not currently authenticated due to uninstaller
|
||||||
|
// Improve later
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/System/Logs", "GET", Summary = "Gets a list of available server log files")]
|
[Route("/System/Logs", "GET", Summary = "Gets a list of available server log files")]
|
||||||
|
|
|
@ -12,6 +12,7 @@ using ServiceStack;
|
||||||
using ServiceStack.Text.Controller;
|
using ServiceStack.Text.Controller;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -175,6 +176,20 @@ namespace MediaBrowser.Api
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("/Users/ForgotPassword", "POST", Summary = "Initiates the forgot password process for a local user")]
|
||||||
|
public class ForgotPassword : IReturn<ForgotPasswordResult>
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "EnteredUsername", IsRequired = false, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||||
|
public string EnteredUsername { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Users/ForgotPassword/Pin", "POST", Summary = "Redeems a forgot password pin")]
|
||||||
|
public class ForgotPasswordPin : IReturn<PinRedeemResult>
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "Pin", IsRequired = false, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||||
|
public string Pin { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class UsersService
|
/// Class UsersService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -217,34 +232,15 @@ namespace MediaBrowser.Api
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
|
// TODO: Uncomment once clients can handle an empty user list (and below)
|
||||||
var isDashboard = string.Equals(authInfo.Client, "Dashboard", StringComparison.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
if (Request.IsLocal && isDashboard)
|
|
||||||
{
|
|
||||||
var users = _userManager.Users
|
|
||||||
.Where(i => !i.Configuration.IsDisabled && !(i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return ToOptimizedResult(users);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Uncomment this once all clients can handle an empty user list.
|
|
||||||
return Get(new GetUsers
|
|
||||||
{
|
|
||||||
IsHidden = false,
|
|
||||||
IsDisabled = false
|
|
||||||
});
|
|
||||||
|
|
||||||
//// TODO: Add or is authenticated
|
|
||||||
//if (Request.IsLocal || IsInLocalNetwork(Request.RemoteIp))
|
//if (Request.IsLocal || IsInLocalNetwork(Request.RemoteIp))
|
||||||
//{
|
{
|
||||||
// return Get(new GetUsers
|
return Get(new GetUsers
|
||||||
// {
|
{
|
||||||
// IsHidden = false,
|
IsHidden = false,
|
||||||
// IsDisabled = false
|
IsDisabled = false
|
||||||
// });
|
});
|
||||||
//}
|
}
|
||||||
|
|
||||||
//// Return empty when external
|
//// Return empty when external
|
||||||
//return ToOptimizedResult(new List<UserDto>());
|
//return ToOptimizedResult(new List<UserDto>());
|
||||||
|
@ -379,7 +375,7 @@ namespace MediaBrowser.Api
|
||||||
RemoteEndPoint = Request.RemoteIp,
|
RemoteEndPoint = Request.RemoteIp,
|
||||||
Username = request.Username
|
Username = request.Username
|
||||||
|
|
||||||
}, Request.IsLocal).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
@ -419,7 +415,7 @@ namespace MediaBrowser.Api
|
||||||
await _userManager.ChangePassword(user, request.NewPassword).ConfigureAwait(false);
|
await _userManager.ChangePassword(user, request.NewPassword).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Posts the specified request.
|
/// Posts the specified request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -510,5 +506,22 @@ namespace MediaBrowser.Api
|
||||||
|
|
||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Posts the specified request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <returns>System.Object.</returns>
|
||||||
|
public object Post(ForgotPassword request)
|
||||||
|
{
|
||||||
|
var isLocal = Request.IsLocal || _networkManager.IsInLocalNetwork(Request.RemoteIp);
|
||||||
|
|
||||||
|
return _userManager.StartForgotPasswordProcess(request.EnteredUsername, isLocal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Post(ForgotPasswordPin request)
|
||||||
|
{
|
||||||
|
return _userManager.RedeemPasswordResetPin(request.Pin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,5 +89,11 @@ namespace MediaBrowser.Controller.Drawing
|
||||||
/// <param name="imageIndex">Index of the image.</param>
|
/// <param name="imageIndex">Index of the image.</param>
|
||||||
/// <returns>Task{System.String}.</returns>
|
/// <returns>Task{System.String}.</returns>
|
||||||
Task<string> GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex);
|
Task<string> GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the supported image output formats.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>ImageOutputFormat[].</returns>
|
||||||
|
ImageOutputFormat[] GetSupportedImageOutputFormats();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
@ -59,12 +60,7 @@ namespace MediaBrowser.Controller.Drawing
|
||||||
|
|
||||||
private bool IsOutputFormatDefault(string originalImagePath)
|
private bool IsOutputFormatDefault(string originalImagePath)
|
||||||
{
|
{
|
||||||
if (OutputFormat == ImageOutputFormat.Original)
|
return string.Equals(Path.GetExtension(originalImagePath), "." + OutputFormat, StringComparison.OrdinalIgnoreCase);
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Equals(Path.GetExtension(originalImagePath), "." + OutputFormat);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Library
|
namespace MediaBrowser.Controller.Library
|
||||||
{
|
{
|
||||||
|
@ -56,6 +57,13 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <returns>User.</returns>
|
/// <returns>User.</returns>
|
||||||
User GetUserById(string id);
|
User GetUserById(string id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the user by.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name.</param>
|
||||||
|
/// <returns>User.</returns>
|
||||||
|
User GetUserByName(string name);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Authenticates a User and returns a result indicating whether or not it succeeded
|
/// Authenticates a User and returns a result indicating whether or not it succeeded
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -141,5 +149,20 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <param name="remoteEndPoint">The remote end point.</param>
|
/// <param name="remoteEndPoint">The remote end point.</param>
|
||||||
/// <returns>Task<System.Boolean>.</returns>
|
/// <returns>Task<System.Boolean>.</returns>
|
||||||
Task<bool> AuthenticateUser(string username, string passwordSha1, string passwordMd5, string remoteEndPoint);
|
Task<bool> AuthenticateUser(string username, string passwordSha1, string passwordMd5, string remoteEndPoint);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts the forgot password process.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enteredUsername">The entered username.</param>
|
||||||
|
/// <param name="isInNetwork">if set to <c>true</c> [is in network].</param>
|
||||||
|
/// <returns>ForgotPasswordResult.</returns>
|
||||||
|
ForgotPasswordResult StartForgotPasswordProcess(string enteredUsername, bool isInNetwork);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Redeems the password reset pin.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pin">The pin.</param>
|
||||||
|
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
|
||||||
|
Task<PinRedeemResult> RedeemPasswordResetPin(string pin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,6 @@ namespace MediaBrowser.Controller.Net
|
||||||
{
|
{
|
||||||
public IAuthService AuthService { get; set; }
|
public IAuthService AuthService { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether or not to allow local unauthenticated access.
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [allow local]; otherwise, <c>false</c>.</value>
|
|
||||||
public bool AllowLocal { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the roles.
|
/// Gets or sets the roles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -70,7 +64,6 @@ namespace MediaBrowser.Controller.Net
|
||||||
{
|
{
|
||||||
bool EscapeParentalControl { get; }
|
bool EscapeParentalControl { get; }
|
||||||
|
|
||||||
bool AllowLocal { get; }
|
|
||||||
IEnumerable<string> GetRoles();
|
IEnumerable<string> GetRoles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,9 +223,8 @@ namespace MediaBrowser.Controller.Session
|
||||||
/// Authenticates the new session.
|
/// Authenticates the new session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
/// <param name="isLocal">if set to <c>true</c> [is local].</param>
|
|
||||||
/// <returns>Task{SessionInfo}.</returns>
|
/// <returns>Task{SessionInfo}.</returns>
|
||||||
Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request, bool isLocal);
|
Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reports the capabilities.
|
/// Reports the capabilities.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Linq;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
@ -16,6 +15,7 @@ using MediaBrowser.Model.Querying;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
|
@ -124,7 +124,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
_logger.Debug("RestartTimer");
|
_logger.Debug("RestartTimer");
|
||||||
_timer.Change(10, GetPlaybackTimerIntervalMs());
|
_timer.Change(10, GetPlaybackTimerIntervalMs());
|
||||||
|
|
||||||
_volumeTimer.Change(100, GetVolumeTimerIntervalMs());
|
_volumeTimer.Change(100, GetVolumeTimerIntervalMs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,8 +146,14 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
_logger.Debug("RestartTimerInactive");
|
_logger.Debug("RestartTimerInactive");
|
||||||
var interval = GetInactiveTimerIntervalMs();
|
var interval = GetInactiveTimerIntervalMs();
|
||||||
|
|
||||||
_timer.Change(interval, interval);
|
if (_timer != null)
|
||||||
_volumeTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
{
|
||||||
|
_timer.Change(interval, interval);
|
||||||
|
}
|
||||||
|
if (_volumeTimer != null)
|
||||||
|
{
|
||||||
|
_volumeTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_timerActive = false;
|
_timerActive = false;
|
||||||
|
|
|
@ -74,8 +74,6 @@
|
||||||
<Compile Include="Providers\SeriesXmlProvider.cs" />
|
<Compile Include="Providers\SeriesXmlProvider.cs" />
|
||||||
<Compile Include="Providers\TrailerXmlProvider.cs" />
|
<Compile Include="Providers\TrailerXmlProvider.cs" />
|
||||||
<Compile Include="Providers\VideoXmlProvider.cs" />
|
<Compile Include="Providers\VideoXmlProvider.cs" />
|
||||||
<Compile Include="Savers\AlbumXmlSaver.cs" />
|
|
||||||
<Compile Include="Savers\ArtistXmlSaver.cs" />
|
|
||||||
<Compile Include="Savers\BoxSetXmlSaver.cs" />
|
<Compile Include="Savers\BoxSetXmlSaver.cs" />
|
||||||
<Compile Include="Savers\ChannelXmlSaver.cs" />
|
<Compile Include="Savers\ChannelXmlSaver.cs" />
|
||||||
<Compile Include="Savers\EpisodeXmlSaver.cs" />
|
<Compile Include="Savers\EpisodeXmlSaver.cs" />
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace MediaBrowser.LocalMetadata.Savers
|
|
||||||
{
|
|
||||||
class AlbumXmlSaver : IMetadataFileSaver
|
|
||||||
{
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "Media Browser Xml";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly IServerConfigurationManager _config;
|
|
||||||
|
|
||||||
public AlbumXmlSaver(IServerConfigurationManager config)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether [is enabled for] [the specified item].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item.</param>
|
|
||||||
/// <param name="updateType">Type of the update.</param>
|
|
||||||
/// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns>
|
|
||||||
public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType)
|
|
||||||
{
|
|
||||||
if (!item.SupportsLocalMetadata)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return item is MusicAlbum && updateType >= ItemUpdateType.MetadataDownload;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Saves the specified item.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <returns>Task.</returns>
|
|
||||||
public void Save(IHasMetadata item, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var builder = new StringBuilder();
|
|
||||||
|
|
||||||
builder.Append("<Item>");
|
|
||||||
|
|
||||||
XmlSaverHelpers.AddCommonNodes((MusicAlbum)item, builder);
|
|
||||||
|
|
||||||
builder.Append("</Item>");
|
|
||||||
|
|
||||||
var xmlFilePath = GetSavePath(item);
|
|
||||||
|
|
||||||
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { }, _config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the save path.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
public string GetSavePath(IHasMetadata item)
|
|
||||||
{
|
|
||||||
return Path.Combine(item.Path, "album.xml");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace MediaBrowser.LocalMetadata.Savers
|
|
||||||
{
|
|
||||||
class ArtistXmlSaver : IMetadataFileSaver
|
|
||||||
{
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "Media Browser Xml";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly IServerConfigurationManager _config;
|
|
||||||
|
|
||||||
public ArtistXmlSaver(IServerConfigurationManager config)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether [is enabled for] [the specified item].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item.</param>
|
|
||||||
/// <param name="updateType">Type of the update.</param>
|
|
||||||
/// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns>
|
|
||||||
public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType)
|
|
||||||
{
|
|
||||||
if (!item.SupportsLocalMetadata)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return item is MusicArtist && updateType >= ItemUpdateType.MetadataDownload;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Saves the specified item.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <returns>Task.</returns>
|
|
||||||
public void Save(IHasMetadata item, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var builder = new StringBuilder();
|
|
||||||
|
|
||||||
builder.Append("<Item>");
|
|
||||||
|
|
||||||
XmlSaverHelpers.AddCommonNodes((MusicArtist)item, builder);
|
|
||||||
|
|
||||||
builder.Append("</Item>");
|
|
||||||
|
|
||||||
var xmlFilePath = GetSavePath(item);
|
|
||||||
|
|
||||||
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { }, _config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the save path.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
public string GetSavePath(IHasMetadata item)
|
|
||||||
{
|
|
||||||
return Path.Combine(item.Path, "artist.xml");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1103,6 +1103,15 @@
|
||||||
<Compile Include="..\MediaBrowser.Model\Users\AuthenticationResult.cs">
|
<Compile Include="..\MediaBrowser.Model\Users\AuthenticationResult.cs">
|
||||||
<Link>Users\AuthenticationResult.cs</Link>
|
<Link>Users\AuthenticationResult.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\MediaBrowser.Model\Users\ForgotPasswordAction.cs">
|
||||||
|
<Link>Users\ForgotPasswordAction.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\MediaBrowser.Model\Users\ForgotPasswordResult.cs">
|
||||||
|
<Link>Users\ForgotPasswordResult.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\MediaBrowser.Model\Users\PinRedeemResult.cs">
|
||||||
|
<Link>Users\PinRedeemResult.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\SharedVersion.cs">
|
<Compile Include="..\SharedVersion.cs">
|
||||||
<Link>Properties\SharedVersion.cs</Link>
|
<Link>Properties\SharedVersion.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -1062,6 +1062,15 @@
|
||||||
<Compile Include="..\MediaBrowser.Model\Users\AuthenticationResult.cs">
|
<Compile Include="..\MediaBrowser.Model\Users\AuthenticationResult.cs">
|
||||||
<Link>Users\AuthenticationResult.cs</Link>
|
<Link>Users\AuthenticationResult.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\MediaBrowser.Model\Users\ForgotPasswordAction.cs">
|
||||||
|
<Link>Users\ForgotPasswordAction.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\MediaBrowser.Model\Users\ForgotPasswordResult.cs">
|
||||||
|
<Link>Users\ForgotPasswordResult.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\MediaBrowser.Model\Users\PinRedeemResult.cs">
|
||||||
|
<Link>Users\PinRedeemResult.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\SharedVersion.cs">
|
<Compile Include="..\SharedVersion.cs">
|
||||||
<Link>Properties\SharedVersion.cs</Link>
|
<Link>Properties\SharedVersion.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -6,10 +6,6 @@ namespace MediaBrowser.Model.Drawing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ImageOutputFormat
|
public enum ImageOutputFormat
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The original
|
|
||||||
/// </summary>
|
|
||||||
Original,
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The BMP
|
/// The BMP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -26,6 +22,9 @@ namespace MediaBrowser.Model.Drawing
|
||||||
/// The PNG
|
/// The PNG
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Png,
|
Png,
|
||||||
|
/// <summary>
|
||||||
|
/// The webp
|
||||||
|
/// </summary>
|
||||||
Webp
|
Webp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dto
|
namespace MediaBrowser.Model.Dto
|
||||||
{
|
{
|
||||||
|
@ -74,7 +73,7 @@ namespace MediaBrowser.Model.Dto
|
||||||
/// Gets or sets the format.
|
/// Gets or sets the format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The format.</value>
|
/// <value>The format.</value>
|
||||||
public ImageOutputFormat Format { get; set; }
|
public ImageOutputFormat? Format { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether [add played indicator].
|
/// Gets or sets a value indicating whether [add played indicator].
|
||||||
|
@ -100,8 +99,6 @@ namespace MediaBrowser.Model.Dto
|
||||||
public ImageOptions()
|
public ImageOptions()
|
||||||
{
|
{
|
||||||
EnableImageEnhancers = true;
|
EnableImageEnhancers = true;
|
||||||
|
|
||||||
Format = ImageOutputFormat.Original;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -407,6 +407,9 @@
|
||||||
<Compile Include="Updates\PackageInfo.cs" />
|
<Compile Include="Updates\PackageInfo.cs" />
|
||||||
<Compile Include="Updates\PackageVersionInfo.cs" />
|
<Compile Include="Updates\PackageVersionInfo.cs" />
|
||||||
<Compile Include="Users\AuthenticationResult.cs" />
|
<Compile Include="Users\AuthenticationResult.cs" />
|
||||||
|
<Compile Include="Users\ForgotPasswordAction.cs" />
|
||||||
|
<Compile Include="Users\ForgotPasswordResult.cs" />
|
||||||
|
<Compile Include="Users\PinRedeemResult.cs" />
|
||||||
<None Include="Fody.targets" />
|
<None Include="Fody.targets" />
|
||||||
<None Include="FodyWeavers.xml" />
|
<None Include="FodyWeavers.xml" />
|
||||||
<None Include="MediaBrowser.Model.snk" />
|
<None Include="MediaBrowser.Model.snk" />
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Model.Users
|
||||||
|
{
|
||||||
|
public enum ForgotPasswordAction
|
||||||
|
{
|
||||||
|
ContactAdmin = 0,
|
||||||
|
PinCode = 1,
|
||||||
|
InNetworkRequired = 2
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Model.Users
|
||||||
|
{
|
||||||
|
public class ForgotPasswordResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the action.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The action.</value>
|
||||||
|
public ForgotPasswordAction Action { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the pin file.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The pin file.</value>
|
||||||
|
public string PinFile { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the pin expiration date.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The pin expiration date.</value>
|
||||||
|
public DateTime? PinExpirationDate { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Model.Users
|
||||||
|
{
|
||||||
|
public class PinRedeemResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this <see cref="PinRedeemResult"/> is success.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if success; otherwise, <c>false</c>.</value>
|
||||||
|
public bool Success { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the users reset.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The users reset.</value>
|
||||||
|
public string[] UsersReset { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -230,7 +230,7 @@ namespace MediaBrowser.Providers.Subtitles
|
||||||
}
|
}
|
||||||
|
|
||||||
Utilities.HttpClient = _httpClient;
|
Utilities.HttpClient = _httpClient;
|
||||||
OpenSubtitles.SetUserAgent("OS Test User Agent");
|
OpenSubtitles.SetUserAgent("mediabrowser.tv");
|
||||||
|
|
||||||
await Login(cancellationToken).ConfigureAwait(false);
|
await Login(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|
|
@ -1027,7 +1027,7 @@ namespace MediaBrowser.Server.Implementations.Connect
|
||||||
{
|
{
|
||||||
var user = e.Argument;
|
var user = e.Argument;
|
||||||
|
|
||||||
//await TryUploadUserPreferences(user, CancellationToken.None).ConfigureAwait(false);
|
await TryUploadUserPreferences(user, CancellationToken.None).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task TryUploadUserPreferences(User user, CancellationToken cancellationToken)
|
private async Task TryUploadUserPreferences(User user, CancellationToken cancellationToken)
|
||||||
|
|
|
@ -129,6 +129,15 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ImageOutputFormat[] GetSupportedImageOutputFormats()
|
||||||
|
{
|
||||||
|
if (_webpAvailable)
|
||||||
|
{
|
||||||
|
return new[] { ImageOutputFormat.Webp, ImageOutputFormat.Gif, ImageOutputFormat.Jpg, ImageOutputFormat.Png };
|
||||||
|
}
|
||||||
|
return new[] { ImageOutputFormat.Gif, ImageOutputFormat.Jpg, ImageOutputFormat.Png };
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<string> ProcessImage(ImageProcessingOptions options)
|
public async Task<string> ProcessImage(ImageProcessingOptions options)
|
||||||
{
|
{
|
||||||
if (options == null)
|
if (options == null)
|
||||||
|
@ -212,9 +221,9 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
var newWidth = Convert.ToInt32(newSize.Width);
|
var newWidth = Convert.ToInt32(newSize.Width);
|
||||||
var newHeight = Convert.ToInt32(newSize.Height);
|
var newHeight = Convert.ToInt32(newSize.Height);
|
||||||
|
|
||||||
var selectedOutputFormat = options.OutputFormat == ImageOutputFormat.Webp && !_webpAvailable
|
var selectedOutputFormat = options.OutputFormat;
|
||||||
? GetFallbackImageFormat(originalImagePath)
|
|
||||||
: options.OutputFormat;
|
_logger.Debug("Processing image to {0}", selectedOutputFormat);
|
||||||
|
|
||||||
// Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
|
// Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
|
||||||
// Also, Webp only supports Format32bppArgb and Format32bppRgb
|
// Also, Webp only supports Format32bppArgb and Format32bppRgb
|
||||||
|
@ -279,11 +288,6 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageOutputFormat GetFallbackImageFormat(string originalImagePath)
|
|
||||||
{
|
|
||||||
return ImageOutputFormat.Png;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SaveToWebP(Bitmap thumbnail, Stream toStream, int quality)
|
private void SaveToWebP(Bitmap thumbnail, Stream toStream, int quality)
|
||||||
{
|
{
|
||||||
new SimpleEncoder().Encode(thumbnail, toStream, quality);
|
new SimpleEncoder().Encode(thumbnail, toStream, quality);
|
||||||
|
@ -479,10 +483,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
|
|
||||||
filename += "datemodified=" + dateModified.Ticks;
|
filename += "datemodified=" + dateModified.Ticks;
|
||||||
|
|
||||||
if (format != ImageOutputFormat.Original)
|
filename += "f=" + format;
|
||||||
{
|
|
||||||
filename += "f=" + format;
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasIndicator = false;
|
var hasIndicator = false;
|
||||||
|
|
||||||
|
|
|
@ -63,17 +63,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
|
||||||
// This code is executed before the service
|
// This code is executed before the service
|
||||||
var auth = AuthorizationContext.GetAuthorizationInfo(req);
|
var auth = AuthorizationContext.GetAuthorizationInfo(req);
|
||||||
|
|
||||||
if (!authAttribtues.AllowLocal || !req.IsLocal)
|
if (!string.IsNullOrWhiteSpace(auth.Token) ||
|
||||||
|
!_config.Configuration.InsecureApps6.Contains(auth.Client ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(auth.Token) ||
|
var valid = IsValidConnectKey(auth.Token);
|
||||||
!_config.Configuration.InsecureApps6.Contains(auth.Client ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var valid = IsValidConnectKey(auth.Token);
|
|
||||||
|
|
||||||
if (!valid)
|
if (!valid)
|
||||||
{
|
{
|
||||||
SessionManager.ValidateSecurityToken(auth.Token);
|
SessionManager.ValidateSecurityToken(auth.Token);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using MediaBrowser.Common.Events;
|
using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Connect;
|
using MediaBrowser.Controller.Connect;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
|
@ -17,9 +18,11 @@ using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Events;
|
using MediaBrowser.Model.Events;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
using MediaBrowser.Server.Implementations.Security;
|
using MediaBrowser.Server.Implementations.Security;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
@ -65,7 +68,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
private readonly Func<IImageProcessor> _imageProcessorFactory;
|
private readonly Func<IImageProcessor> _imageProcessorFactory;
|
||||||
private readonly Func<IDtoService> _dtoServiceFactory;
|
private readonly Func<IDtoService> _dtoServiceFactory;
|
||||||
private readonly Func<IConnectManager> _connectFactory;
|
private readonly Func<IConnectManager> _connectFactory;
|
||||||
private readonly IApplicationHost _appHost;
|
private readonly IServerApplicationHost _appHost;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="UserManager" /> class.
|
/// Initializes a new instance of the <see cref="UserManager" /> class.
|
||||||
|
@ -73,7 +76,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
/// <param name="configurationManager">The configuration manager.</param>
|
/// <param name="configurationManager">The configuration manager.</param>
|
||||||
/// <param name="userRepository">The user repository.</param>
|
/// <param name="userRepository">The user repository.</param>
|
||||||
public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IApplicationHost appHost)
|
public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
UserRepository = userRepository;
|
UserRepository = userRepository;
|
||||||
|
@ -85,6 +88,8 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
ConfigurationManager = configurationManager;
|
ConfigurationManager = configurationManager;
|
||||||
Users = new List<User>();
|
Users = new List<User>();
|
||||||
|
|
||||||
|
DeletePinFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region UserUpdated Event
|
#region UserUpdated Event
|
||||||
|
@ -145,6 +150,16 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
return GetUserById(new Guid(id));
|
return GetUserById(new Guid(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public User GetUserByName(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("name");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Users.FirstOrDefault(u => string.Equals(u.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Initialize()
|
public async Task Initialize()
|
||||||
{
|
{
|
||||||
Users = await LoadUsers().ConfigureAwait(false);
|
Users = await LoadUsers().ConfigureAwait(false);
|
||||||
|
@ -599,5 +614,157 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
|
|
||||||
EventHelper.FireEventIfNotNull(UserConfigurationUpdated, this, new GenericEventArgs<User> { Argument = user }, _logger);
|
EventHelper.FireEventIfNotNull(UserConfigurationUpdated, this, new GenericEventArgs<User> { Argument = user }, _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string PasswordResetFile
|
||||||
|
{
|
||||||
|
get { return Path.Combine(ConfigurationManager.ApplicationPaths.ProgramDataPath, "passwordreset.txt"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _lastPin;
|
||||||
|
private PasswordPinCreationResult _lastPasswordPinCreationResult;
|
||||||
|
private int _pinAttempts;
|
||||||
|
|
||||||
|
private PasswordPinCreationResult CreatePasswordResetPin()
|
||||||
|
{
|
||||||
|
var num = new Random().Next(1, 9999);
|
||||||
|
|
||||||
|
var path = PasswordResetFile;
|
||||||
|
|
||||||
|
var pin = num.ToString("0000", CultureInfo.InvariantCulture);
|
||||||
|
_lastPin = pin;
|
||||||
|
|
||||||
|
var time = TimeSpan.FromMinutes(5);
|
||||||
|
var expiration = DateTime.UtcNow.Add(time);
|
||||||
|
|
||||||
|
var text = new StringBuilder();
|
||||||
|
|
||||||
|
var info = _appHost.GetSystemInfo();
|
||||||
|
var localAddress = info.LocalAddress ?? string.Empty;
|
||||||
|
|
||||||
|
text.AppendLine("Use your web browser to visit:");
|
||||||
|
text.AppendLine(string.Empty);
|
||||||
|
text.AppendLine(localAddress + "/mediabrowser/web/forgotpasswordpin.html");
|
||||||
|
text.AppendLine(string.Empty);
|
||||||
|
text.AppendLine("Enter the following pin code:");
|
||||||
|
text.AppendLine(string.Empty);
|
||||||
|
text.AppendLine(pin);
|
||||||
|
text.AppendLine(string.Empty);
|
||||||
|
text.AppendLine("The pin code will expire at " + expiration.ToLocalTime().ToShortDateString() + " " + expiration.ToLocalTime().ToShortTimeString());
|
||||||
|
|
||||||
|
File.WriteAllText(path, text.ToString(), Encoding.UTF8);
|
||||||
|
|
||||||
|
var result = new PasswordPinCreationResult
|
||||||
|
{
|
||||||
|
PinFile = path,
|
||||||
|
ExpirationDate = expiration
|
||||||
|
};
|
||||||
|
|
||||||
|
_lastPasswordPinCreationResult = result;
|
||||||
|
_pinAttempts = 0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForgotPasswordResult StartForgotPasswordProcess(string enteredUsername, bool isInNetwork)
|
||||||
|
{
|
||||||
|
DeletePinFile();
|
||||||
|
|
||||||
|
var user = string.IsNullOrWhiteSpace(enteredUsername) ?
|
||||||
|
null :
|
||||||
|
GetUserByName(enteredUsername);
|
||||||
|
|
||||||
|
if (user != null && user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Unable to process forgot password request for guests.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var action = ForgotPasswordAction.InNetworkRequired;
|
||||||
|
string pinFile = null;
|
||||||
|
DateTime? expirationDate = null;
|
||||||
|
|
||||||
|
if (user != null && !user.Configuration.IsAdministrator)
|
||||||
|
{
|
||||||
|
action = ForgotPasswordAction.ContactAdmin;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isInNetwork)
|
||||||
|
{
|
||||||
|
action = ForgotPasswordAction.PinCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = CreatePasswordResetPin();
|
||||||
|
pinFile = result.PinFile;
|
||||||
|
expirationDate = result.ExpirationDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ForgotPasswordResult
|
||||||
|
{
|
||||||
|
Action = action,
|
||||||
|
PinFile = pinFile,
|
||||||
|
PinExpirationDate = expirationDate
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PinRedeemResult> RedeemPasswordResetPin(string pin)
|
||||||
|
{
|
||||||
|
DeletePinFile();
|
||||||
|
|
||||||
|
var usersReset = new List<string>();
|
||||||
|
|
||||||
|
var valid = !string.IsNullOrWhiteSpace(_lastPin) &&
|
||||||
|
string.Equals(_lastPin, pin, StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
_lastPasswordPinCreationResult != null &&
|
||||||
|
_lastPasswordPinCreationResult.ExpirationDate > DateTime.UtcNow;
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
_lastPin = null;
|
||||||
|
_lastPasswordPinCreationResult = null;
|
||||||
|
|
||||||
|
var users = Users.Where(i => !i.ConnectLinkType.HasValue || i.ConnectLinkType.Value != UserLinkType.Guest)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var user in users)
|
||||||
|
{
|
||||||
|
await ResetPassword(user).ConfigureAwait(false);
|
||||||
|
usersReset.Add(user.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pinAttempts++;
|
||||||
|
if (_pinAttempts >= 3)
|
||||||
|
{
|
||||||
|
_lastPin = null;
|
||||||
|
_lastPasswordPinCreationResult = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PinRedeemResult
|
||||||
|
{
|
||||||
|
Success = valid,
|
||||||
|
UsersReset = usersReset.ToArray()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeletePinFile()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(PasswordResetFile);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PasswordPinCreationResult
|
||||||
|
{
|
||||||
|
public string PinFile { get; set; }
|
||||||
|
public DateTime ExpirationDate { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -624,5 +624,12 @@
|
||||||
"MessageLoggedOutParentalControl": "Access is currently restricted. Please try again later.",
|
"MessageLoggedOutParentalControl": "Access is currently restricted. Please try again later.",
|
||||||
"DefaultErrorMessage": "There was an error processing the request. Please try again later.",
|
"DefaultErrorMessage": "There was an error processing the request. Please try again later.",
|
||||||
"ButtonAccept": "Accept",
|
"ButtonAccept": "Accept",
|
||||||
"ButtonReject": "Reject"
|
"ButtonReject": "Reject",
|
||||||
|
"HeaderForgotPassword": "Forgot Password",
|
||||||
|
"MessageContactAdminToResetPassword": "Please contact your system administrator to reset your password.",
|
||||||
|
"MessageForgotPasswordInNetworkRequired": "Please try again within your home network to initiate the password reset process.",
|
||||||
|
"MessageForgotPasswordFileCreated": "The following file has been created on your server and contains instructions on how to proceed:",
|
||||||
|
"MessageForgotPasswordFileExpiration": "The reset pin will expire at {0}.",
|
||||||
|
"MessageInvalidForgotPasswordPin": "An invalid or expired pin was entered. Please try again.",
|
||||||
|
"MessagePasswordResetForUsers": "Passwords have been reset for the following users:"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1270,5 +1270,11 @@
|
||||||
"LabelSelectLastestItemsFolders": "Include media from the following sections in Latest Items",
|
"LabelSelectLastestItemsFolders": "Include media from the following sections in Latest Items",
|
||||||
"HeaderShareMediaFolders": "Share Media Folders",
|
"HeaderShareMediaFolders": "Share Media Folders",
|
||||||
"MessageGuestSharingPermissionsHelp": "Most features are initially unavailable to guests but can be enabled as needed.",
|
"MessageGuestSharingPermissionsHelp": "Most features are initially unavailable to guests but can be enabled as needed.",
|
||||||
"HeaderInvitations": "Invitations"
|
"HeaderInvitations": "Invitations",
|
||||||
|
"LabelForgotPasswordUsernameHelp": "Enter your username, if you remember it.",
|
||||||
|
"HeaderForgotPassword": "Forgot Password",
|
||||||
|
"TitleForgotPassword": "Forgot Password",
|
||||||
|
"TitlePasswordReset": "Password Reset",
|
||||||
|
"LabelPasswordRecoveryPinCode": "Pin code:",
|
||||||
|
"HeaderPasswordReset": "Password Reset"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1300,23 +1300,16 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
/// Authenticates the new session.
|
/// Authenticates the new session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
/// <param name="isLocal">if set to <c>true</c> [is local].</param>
|
|
||||||
/// <returns>Task{SessionInfo}.</returns>
|
/// <returns>Task{SessionInfo}.</returns>
|
||||||
/// <exception cref="AuthenticationException">Invalid user or password entered.</exception>
|
/// <exception cref="AuthenticationException">Invalid user or password entered.</exception>
|
||||||
/// <exception cref="System.UnauthorizedAccessException">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>
|
/// <exception cref="UnauthorizedAccessException">Invalid user or password entered.</exception>
|
||||||
public async Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request,
|
public async Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request)
|
||||||
bool isLocal)
|
|
||||||
{
|
{
|
||||||
var user = _userManager.Users
|
var user = _userManager.Users
|
||||||
.FirstOrDefault(i => string.Equals(request.Username, i.Name, StringComparison.OrdinalIgnoreCase));
|
.FirstOrDefault(i => string.Equals(request.Username, i.Name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
var allowWithoutPassword = isLocal &&
|
var result = await _userManager.AuthenticateUser(request.Username, request.PasswordSha1, request.PasswordMd5, request.RemoteEndPoint).ConfigureAwait(false);
|
||||||
string.Equals(request.App, "Dashboard", StringComparison.OrdinalIgnoreCase)
|
|
||||||
&& !(user != null && user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest);
|
|
||||||
|
|
||||||
var result = allowWithoutPassword ||
|
|
||||||
await _userManager.AuthenticateUser(request.Username, request.PasswordSha1, request.PasswordMd5, request.RemoteEndPoint).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,7 +36,9 @@ namespace MediaBrowser.ServerApplication
|
||||||
var options = new StartupOptions();
|
var options = new StartupOptions();
|
||||||
_isRunningAsService = options.ContainsOption("-service");
|
_isRunningAsService = options.ContainsOption("-service");
|
||||||
|
|
||||||
var applicationPath = Process.GetCurrentProcess().MainModule.FileName;
|
var currentProcess = Process.GetCurrentProcess();
|
||||||
|
|
||||||
|
var applicationPath = currentProcess.MainModule.FileName;
|
||||||
|
|
||||||
var appPaths = CreateApplicationPaths(applicationPath, _isRunningAsService);
|
var appPaths = CreateApplicationPaths(applicationPath, _isRunningAsService);
|
||||||
|
|
||||||
|
@ -84,8 +86,6 @@ namespace MediaBrowser.ServerApplication
|
||||||
|
|
||||||
RunServiceInstallationIfNeeded(applicationPath);
|
RunServiceInstallationIfNeeded(applicationPath);
|
||||||
|
|
||||||
var currentProcess = Process.GetCurrentProcess();
|
|
||||||
|
|
||||||
if (IsAlreadyRunning(applicationPath, currentProcess))
|
if (IsAlreadyRunning(applicationPath, currentProcess))
|
||||||
{
|
{
|
||||||
logger.Info("Shutting down because another instance of Media Browser Server is already running.");
|
logger.Info("Shutting down because another instance of Media Browser Server is already running.");
|
||||||
|
|
|
@ -374,6 +374,8 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
"externalplayer.js",
|
"externalplayer.js",
|
||||||
"favorites.js",
|
"favorites.js",
|
||||||
|
"forgotpassword.js",
|
||||||
|
"forgotpasswordpin.js",
|
||||||
"gamesrecommendedpage.js",
|
"gamesrecommendedpage.js",
|
||||||
"gamesystemspage.js",
|
"gamesystemspage.js",
|
||||||
"gamespage.js",
|
"gamespage.js",
|
||||||
|
|
|
@ -90,6 +90,15 @@
|
||||||
<Content Include="dashboard-ui\css\images\server.png">
|
<Content Include="dashboard-ui\css\images\server.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\forgotpasswordpin.html">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\scripts\forgotpassword.js">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\scripts\forgotpasswordpin.js">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\scripts\selectserver.js">
|
<Content Include="dashboard-ui\scripts\selectserver.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -2232,6 +2241,9 @@
|
||||||
<Content Include="dashboard-ui\index.html">
|
<Content Include="dashboard-ui\index.html">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\forgotpassword.html">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="dashboard-ui\advanced.html">
|
<Content Include="dashboard-ui\advanced.html">
|
||||||
|
|
Loading…
Reference in New Issue