aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2014-11-08 22:18:14 -0500
committerLuke Pulverenti <luke.pulverenti@gmail.com>2014-11-08 22:18:14 -0500
commit40897bac1494791e1ec6abcfe85cda27d4664a32 (patch)
tree4788db3f5e35a3a06c9668f4460299c4f4a17ca1
parent0ef95fb19cde8f4443e2cede94ec21583c3dc9d7 (diff)
fixes #941 - Rework password recovery and remove IsLocal checks
-rw-r--r--MediaBrowser.Api/Images/ImageRequest.cs7
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs55
-rw-r--r--MediaBrowser.Api/Playback/Hls/MpegDashService.cs7
-rw-r--r--MediaBrowser.Api/System/SystemService.cs3
-rw-r--r--MediaBrowser.Api/UserService.cs69
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs6
-rw-r--r--MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs8
-rw-r--r--MediaBrowser.Controller/Library/IUserManager.cs23
-rw-r--r--MediaBrowser.Controller/Net/AuthenticatedAttribute.cs7
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs3
-rw-r--r--MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs4
-rw-r--r--MediaBrowser.Dlna/PlayTo/Device.cs11
-rw-r--r--MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj2
-rw-r--r--MediaBrowser.LocalMetadata/Savers/AlbumXmlSaver.cs76
-rw-r--r--MediaBrowser.LocalMetadata/Savers/ArtistXmlSaver.cs76
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj9
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj9
-rw-r--r--MediaBrowser.Model/Drawing/ImageOutputFormat.cs7
-rw-r--r--MediaBrowser.Model/Dto/ImageOptions.cs5
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj3
-rw-r--r--MediaBrowser.Model/Users/ForgotPasswordAction.cs10
-rw-r--r--MediaBrowser.Model/Users/ForgotPasswordResult.cs23
-rw-r--r--MediaBrowser.Model/Users/PinRedeemResult.cs17
-rw-r--r--MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Connect/ConnectManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs25
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs15
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserManager.cs171
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json9
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/server.json8
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs11
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs6
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs2
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj12
34 files changed, 444 insertions, 259 deletions
diff --git a/MediaBrowser.Api/Images/ImageRequest.cs b/MediaBrowser.Api/Images/ImageRequest.cs
index 718d5f402..cdd348bb5 100644
--- a/MediaBrowser.Api/Images/ImageRequest.cs
+++ b/MediaBrowser.Api/Images/ImageRequest.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Entities;
using ServiceStack;
namespace MediaBrowser.Api.Images
@@ -54,7 +53,7 @@ namespace MediaBrowser.Api.Images
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")]
- 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")]
public bool AddPlayedIndicator { get; set; }
@@ -71,8 +70,6 @@ namespace MediaBrowser.Api.Images
public ImageRequest()
{
EnableImageEnhancers = true;
-
- Format = ImageOutputFormat.Original;
}
}
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index ca54249b3..7fc43e164 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -542,7 +542,8 @@ namespace MediaBrowser.Api.Images
}).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));
@@ -562,6 +563,7 @@ namespace MediaBrowser.Api.Images
return GetImageResult(item,
request,
imageInfo,
+ format,
supportedImageEnhancers,
contentType,
cacheDuration,
@@ -573,6 +575,7 @@ namespace MediaBrowser.Api.Images
private async Task<object> GetImageResult(IHasImages item,
ImageRequest request,
ItemImageInfo image,
+ ImageOutputFormat format,
List<IImageEnhancer> enhancers,
string contentType,
TimeSpan? cacheDuration,
@@ -598,11 +601,11 @@ namespace MediaBrowser.Api.Images
MaxWidth = request.MaxWidth,
Quality = request.Quality,
Width = request.Width,
- OutputFormat = request.Format,
AddPlayedIndicator = request.AddPlayedIndicator,
PercentPlayed = request.PercentPlayed ?? 0,
UnplayedCount = request.UnplayedCount,
- BackgroundColor = request.BackgroundColor
+ BackgroundColor = request.BackgroundColor,
+ OutputFormat = format
};
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)
{
if (format == ImageOutputFormat.Bmp)
diff --git a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
index 7135d9b84..3c1f07c5f 100644
--- a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
+++ b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
@@ -598,6 +598,8 @@ namespace MediaBrowser.Api.Playback.Hls
var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
+ args += " -r 24 -g 24";
+
// Add resolution params, if specified
if (!hasGraphicalSubs)
{
@@ -615,6 +617,9 @@ namespace MediaBrowser.Api.Playback.Hls
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 inputModifier = GetInputModifier(state);
@@ -624,7 +629,7 @@ namespace MediaBrowser.Api.Playback.Hls
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,
GetInputArgument(transcodingJobId, state),
threads,
diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs
index aa01e1b65..3b8eb7b6f 100644
--- a/MediaBrowser.Api/System/SystemService.cs
+++ b/MediaBrowser.Api/System/SystemService.cs
@@ -44,9 +44,10 @@ namespace MediaBrowser.Api.System
/// This is currently not authenticated because the uninstaller needs to be able to shutdown the server.
/// </summary>
[Route("/System/Shutdown", "POST", Summary = "Shuts down the application")]
- [Authenticated(AllowLocal = true)]
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")]
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index 19bfb821f..9bd85426d 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -12,6 +12,7 @@ using ServiceStack;
using ServiceStack.Text.Controller;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -175,6 +176,20 @@ namespace MediaBrowser.Api
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>
/// Class UsersService
/// </summary>
@@ -217,35 +232,16 @@ namespace MediaBrowser.Api
});
}
- var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
- var isDashboard = string.Equals(authInfo.Client, "Dashboard", StringComparison.OrdinalIgnoreCase);
-
- if (Request.IsLocal && isDashboard)
+ // TODO: Uncomment once clients can handle an empty user list (and below)
+ //if (Request.IsLocal || IsInLocalNetwork(Request.RemoteIp))
{
- var users = _userManager.Users
- .Where(i => !i.Configuration.IsDisabled && !(i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest))
- .ToList();
-
- return ToOptimizedResult(users);
+ return Get(new GetUsers
+ {
+ IsHidden = false,
+ IsDisabled = false
+ });
}
- // 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))
- //{
- // return Get(new GetUsers
- // {
- // IsHidden = false,
- // IsDisabled = false
- // });
- //}
-
//// Return empty when external
//return ToOptimizedResult(new List<UserDto>());
}
@@ -379,7 +375,7 @@ namespace MediaBrowser.Api
RemoteEndPoint = Request.RemoteIp,
Username = request.Username
- }, Request.IsLocal).ConfigureAwait(false);
+ }).ConfigureAwait(false);
return ToOptimizedResult(result);
}
@@ -419,7 +415,7 @@ namespace MediaBrowser.Api
await _userManager.ChangePassword(user, request.NewPassword).ConfigureAwait(false);
}
}
-
+
/// <summary>
/// Posts the specified request.
/// </summary>
@@ -510,5 +506,22 @@ namespace MediaBrowser.Api
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);
+ }
}
}
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index a0128f111..3bd333527 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -89,5 +89,11 @@ namespace MediaBrowser.Controller.Drawing
/// <param name="imageIndex">Index of the image.</param>
/// <returns>Task{System.String}.</returns>
Task<string> GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex);
+
+ /// <summary>
+ /// Gets the supported image output formats.
+ /// </summary>
+ /// <returns>ImageOutputFormat[].</returns>
+ ImageOutputFormat[] GetSupportedImageOutputFormats();
}
}
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index fbbf21797..b99186f37 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing;
+using System;
using System.Collections.Generic;
using System.IO;
@@ -59,12 +60,7 @@ namespace MediaBrowser.Controller.Drawing
private bool IsOutputFormatDefault(string originalImagePath)
{
- if (OutputFormat == ImageOutputFormat.Original)
- {
- return true;
- }
-
- return string.Equals(Path.GetExtension(originalImagePath), "." + OutputFormat);
+ return string.Equals(Path.GetExtension(originalImagePath), "." + OutputFormat, StringComparison.OrdinalIgnoreCase);
}
}
}
diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs
index 6e084e9d8..bd44f786f 100644
--- a/MediaBrowser.Controller/Library/IUserManager.cs
+++ b/MediaBrowser.Controller/Library/IUserManager.cs
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Library
{
@@ -57,6 +58,13 @@ namespace MediaBrowser.Controller.Library
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>
/// Authenticates a User and returns a result indicating whether or not it succeeded
/// </summary>
/// <param name="username">The username.</param>
@@ -141,5 +149,20 @@ namespace MediaBrowser.Controller.Library
/// <param name="remoteEndPoint">The remote end point.</param>
/// <returns>Task&lt;System.Boolean&gt;.</returns>
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);
}
}
diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
index 83e404dfc..17c91c977 100644
--- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
+++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
@@ -10,12 +10,6 @@ namespace MediaBrowser.Controller.Net
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>
/// Gets or sets the roles.
/// </summary>
/// <value>The roles.</value>
@@ -70,7 +64,6 @@ namespace MediaBrowser.Controller.Net
{
bool EscapeParentalControl { get; }
- bool AllowLocal { get; }
IEnumerable<string> GetRoles();
}
}
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index c048e3fab..8bc516887 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -223,9 +223,8 @@ namespace MediaBrowser.Controller.Session
/// Authenticates the new session.
/// </summary>
/// <param name="request">The request.</param>
- /// <param name="isLocal">if set to <c>true</c> [is local].</param>
/// <returns>Task{SessionInfo}.</returns>
- Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request, bool isLocal);
+ Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request);
/// <summary>
/// Reports the capabilities.
diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
index 5d9bd0c7d..879f3045f 100644
--- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
@@ -1,5 +1,4 @@
-using System.Linq;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
@@ -16,6 +15,7 @@ using MediaBrowser.Model.Querying;
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs
index f67094554..c43efcd1d 100644
--- a/MediaBrowser.Dlna/PlayTo/Device.cs
+++ b/MediaBrowser.Dlna/PlayTo/Device.cs
@@ -124,7 +124,6 @@ namespace MediaBrowser.Dlna.PlayTo
{
_logger.Debug("RestartTimer");
_timer.Change(10, GetPlaybackTimerIntervalMs());
-
_volumeTimer.Change(100, GetVolumeTimerIntervalMs());
}
@@ -147,8 +146,14 @@ namespace MediaBrowser.Dlna.PlayTo
_logger.Debug("RestartTimerInactive");
var interval = GetInactiveTimerIntervalMs();
- _timer.Change(interval, interval);
- _volumeTimer.Change(Timeout.Infinite, Timeout.Infinite);
+ if (_timer != null)
+ {
+ _timer.Change(interval, interval);
+ }
+ if (_volumeTimer != null)
+ {
+ _volumeTimer.Change(Timeout.Infinite, Timeout.Infinite);
+ }
}
_timerActive = false;
diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
index 821ac7b7f..1daf0e4ac 100644
--- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
+++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
@@ -74,8 +74,6 @@
<Compile Include="Providers\SeriesXmlProvider.cs" />
<Compile Include="Providers\TrailerXmlProvider.cs" />
<Compile Include="Providers\VideoXmlProvider.cs" />
- <Compile Include="Savers\AlbumXmlSaver.cs" />
- <Compile Include="Savers\ArtistXmlSaver.cs" />
<Compile Include="Savers\BoxSetXmlSaver.cs" />
<Compile Include="Savers\ChannelXmlSaver.cs" />
<Compile Include="Savers\EpisodeXmlSaver.cs" />
diff --git a/MediaBrowser.LocalMetadata/Savers/AlbumXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/AlbumXmlSaver.cs
deleted file mode 100644
index ba334da8c..000000000
--- a/MediaBrowser.LocalMetadata/Savers/AlbumXmlSaver.cs
+++ /dev/null
@@ -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");
- }
- }
-}
diff --git a/MediaBrowser.LocalMetadata/Savers/ArtistXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/ArtistXmlSaver.cs
deleted file mode 100644
index 5b74db232..000000000
--- a/MediaBrowser.LocalMetadata/Savers/ArtistXmlSaver.cs
+++ /dev/null
@@ -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");
- }
- }
-}
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index c1f8ef7d5..b73dae27b 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -1103,6 +1103,15 @@
<Compile Include="..\MediaBrowser.Model\Users\AuthenticationResult.cs">
<Link>Users\AuthenticationResult.cs</Link>
</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">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index 731af59d3..68c65de1c 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -1062,6 +1062,15 @@
<Compile Include="..\MediaBrowser.Model\Users\AuthenticationResult.cs">
<Link>Users\AuthenticationResult.cs</Link>
</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">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/Drawing/ImageOutputFormat.cs b/MediaBrowser.Model/Drawing/ImageOutputFormat.cs
index 824970073..ec32f64f2 100644
--- a/MediaBrowser.Model/Drawing/ImageOutputFormat.cs
+++ b/MediaBrowser.Model/Drawing/ImageOutputFormat.cs
@@ -7,10 +7,6 @@ namespace MediaBrowser.Model.Drawing
public enum ImageOutputFormat
{
/// <summary>
- /// The original
- /// </summary>
- Original,
- /// <summary>
/// The BMP
/// </summary>
Bmp,
@@ -26,6 +22,9 @@ namespace MediaBrowser.Model.Drawing
/// The PNG
/// </summary>
Png,
+ /// <summary>
+ /// The webp
+ /// </summary>
Webp
}
}
diff --git a/MediaBrowser.Model/Dto/ImageOptions.cs b/MediaBrowser.Model/Dto/ImageOptions.cs
index 08ac7906a..037be4a87 100644
--- a/MediaBrowser.Model/Dto/ImageOptions.cs
+++ b/MediaBrowser.Model/Dto/ImageOptions.cs
@@ -1,6 +1,5 @@
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
-using System;
namespace MediaBrowser.Model.Dto
{
@@ -74,7 +73,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the format.
/// </summary>
/// <value>The format.</value>
- public ImageOutputFormat Format { get; set; }
+ public ImageOutputFormat? Format { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [add played indicator].
@@ -100,8 +99,6 @@ namespace MediaBrowser.Model.Dto
public ImageOptions()
{
EnableImageEnhancers = true;
-
- Format = ImageOutputFormat.Original;
}
}
}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 8f84edb25..3a6e8d3e5 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -407,6 +407,9 @@
<Compile Include="Updates\PackageInfo.cs" />
<Compile Include="Updates\PackageVersionInfo.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="FodyWeavers.xml" />
<None Include="MediaBrowser.Model.snk" />
diff --git a/MediaBrowser.Model/Users/ForgotPasswordAction.cs b/MediaBrowser.Model/Users/ForgotPasswordAction.cs
new file mode 100644
index 000000000..f75b1d74b
--- /dev/null
+++ b/MediaBrowser.Model/Users/ForgotPasswordAction.cs
@@ -0,0 +1,10 @@
+
+namespace MediaBrowser.Model.Users
+{
+ public enum ForgotPasswordAction
+ {
+ ContactAdmin = 0,
+ PinCode = 1,
+ InNetworkRequired = 2
+ }
+}
diff --git a/MediaBrowser.Model/Users/ForgotPasswordResult.cs b/MediaBrowser.Model/Users/ForgotPasswordResult.cs
new file mode 100644
index 000000000..7dbb1e96b
--- /dev/null
+++ b/MediaBrowser.Model/Users/ForgotPasswordResult.cs
@@ -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; }
+ }
+}
diff --git a/MediaBrowser.Model/Users/PinRedeemResult.cs b/MediaBrowser.Model/Users/PinRedeemResult.cs
new file mode 100644
index 000000000..6a01bf2d4
--- /dev/null
+++ b/MediaBrowser.Model/Users/PinRedeemResult.cs
@@ -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; }
+ }
+}
diff --git a/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs b/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs
index 722d0d3f3..289c5661f 100644
--- a/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs
+++ b/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs
@@ -230,7 +230,7 @@ namespace MediaBrowser.Providers.Subtitles
}
Utilities.HttpClient = _httpClient;
- OpenSubtitles.SetUserAgent("OS Test User Agent");
+ OpenSubtitles.SetUserAgent("mediabrowser.tv");
await Login(cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
index f2ab64a52..f0d3b76e5 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
@@ -1027,7 +1027,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
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)
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
index c8e923b12..feda361c8 100644
--- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
@@ -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)
{
if (options == null)
@@ -212,9 +221,9 @@ namespace MediaBrowser.Server.Implementations.Drawing
var newWidth = Convert.ToInt32(newSize.Width);
var newHeight = Convert.ToInt32(newSize.Height);
- var selectedOutputFormat = options.OutputFormat == ImageOutputFormat.Webp && !_webpAvailable
- ? GetFallbackImageFormat(originalImagePath)
- : options.OutputFormat;
+ var selectedOutputFormat = 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
// 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)
{
new SimpleEncoder().Encode(thumbnail, toStream, quality);
@@ -479,10 +483,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
filename += "datemodified=" + dateModified.Ticks;
- if (format != ImageOutputFormat.Original)
- {
- filename += "f=" + format;
- }
+ filename += "f=" + format;
var hasIndicator = false;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
index 295f0c775..dde61079b 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
@@ -63,17 +63,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
// This code is executed before the service
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) ||
- !_config.Configuration.InsecureApps6.Contains(auth.Client ?? string.Empty, StringComparer.OrdinalIgnoreCase))
- {
- var valid = IsValidConnectKey(auth.Token);
+ var valid = IsValidConnectKey(auth.Token);
- if (!valid)
- {
- SessionManager.ValidateSecurityToken(auth.Token);
- }
+ if (!valid)
+ {
+ SessionManager.ValidateSecurityToken(auth.Token);
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs
index 55311ed8d..9e3fd3f17 100644
--- a/MediaBrowser.Server.Implementations/Library/UserManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Connect;
using MediaBrowser.Controller.Drawing;
@@ -17,9 +18,11 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Users;
using MediaBrowser.Server.Implementations.Security;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
@@ -65,7 +68,7 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly Func<IImageProcessor> _imageProcessorFactory;
private readonly Func<IDtoService> _dtoServiceFactory;
private readonly Func<IConnectManager> _connectFactory;
- private readonly IApplicationHost _appHost;
+ private readonly IServerApplicationHost _appHost;
/// <summary>
/// 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="configurationManager">The configuration manager.</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;
UserRepository = userRepository;
@@ -85,6 +88,8 @@ namespace MediaBrowser.Server.Implementations.Library
_appHost = appHost;
ConfigurationManager = configurationManager;
Users = new List<User>();
+
+ DeletePinFile();
}
#region UserUpdated Event
@@ -145,6 +150,16 @@ namespace MediaBrowser.Server.Implementations.Library
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()
{
Users = await LoadUsers().ConfigureAwait(false);
@@ -599,5 +614,157 @@ namespace MediaBrowser.Server.Implementations.Library
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; }
+ }
+
}
}
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
index 5920ab6f0..a484cbbb8 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
@@ -624,5 +624,12 @@
"MessageLoggedOutParentalControl": "Access is currently restricted. Please try again later.",
"DefaultErrorMessage": "There was an error processing the request. Please try again later.",
"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:"
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json
index 099f3f75b..307490a19 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -1270,5 +1270,11 @@
"LabelSelectLastestItemsFolders": "Include media from the following sections in Latest Items",
"HeaderShareMediaFolders": "Share Media Folders",
"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"
}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index ac8068744..d6db836cc 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -1300,23 +1300,16 @@ namespace MediaBrowser.Server.Implementations.Session
/// Authenticates the new session.
/// </summary>
/// <param name="request">The request.</param>
- /// <param name="isLocal">if set to <c>true</c> [is local].</param>
/// <returns>Task{SessionInfo}.</returns>
/// <exception cref="AuthenticationException">Invalid user or password entered.</exception>
/// <exception cref="System.UnauthorizedAccessException">Invalid user or password entered.</exception>
/// <exception cref="UnauthorizedAccessException">Invalid user or password entered.</exception>
- public async Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request,
- bool isLocal)
+ public async Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request)
{
var user = _userManager.Users
.FirstOrDefault(i => string.Equals(request.Username, i.Name, StringComparison.OrdinalIgnoreCase));
- var allowWithoutPassword = isLocal &&
- 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);
+ var result = await _userManager.AuthenticateUser(request.Username, request.PasswordSha1, request.PasswordMd5, request.RemoteEndPoint).ConfigureAwait(false);
if (!result)
{
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index e6cea5463..e80284356 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -36,7 +36,9 @@ namespace MediaBrowser.ServerApplication
var options = new StartupOptions();
_isRunningAsService = options.ContainsOption("-service");
- var applicationPath = Process.GetCurrentProcess().MainModule.FileName;
+ var currentProcess = Process.GetCurrentProcess();
+
+ var applicationPath = currentProcess.MainModule.FileName;
var appPaths = CreateApplicationPaths(applicationPath, _isRunningAsService);
@@ -84,8 +86,6 @@ namespace MediaBrowser.ServerApplication
RunServiceInstallationIfNeeded(applicationPath);
- var currentProcess = Process.GetCurrentProcess();
-
if (IsAlreadyRunning(applicationPath, currentProcess))
{
logger.Info("Shutting down because another instance of Media Browser Server is already running.");
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index 68de9ac49..18f2e54a3 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -374,6 +374,8 @@ namespace MediaBrowser.WebDashboard.Api
"externalplayer.js",
"favorites.js",
+ "forgotpassword.js",
+ "forgotpasswordpin.js",
"gamesrecommendedpage.js",
"gamesystemspage.js",
"gamespage.js",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 9a9552d5d..3dded5d98 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -90,6 +90,15 @@
<Content Include="dashboard-ui\css\images\server.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</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">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -2232,6 +2241,9 @@
<Content Include="dashboard-ui\index.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\forgotpassword.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
</ItemGroup>
<ItemGroup>
<Content Include="dashboard-ui\advanced.html">