aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Server.Implementations')
-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
7 files changed, 206 insertions, 35 deletions
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)
{