@ -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 I ApplicationHost _appHost ;
private readonly I Server ApplicationHost _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 , I ApplicationHost appHost )
public UserManager ( ILogger logger , IServerConfigurationManager configurationManager , IUserRepository userRepository , IXmlSerializer xmlSerializer , INetworkManager networkManager , Func < IImageProcessor > imageProcessorFactory , Func < IDtoService > dtoServiceFactory , Func < IConnectManager > connectFactory , I Server ApplicationHost 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 ; }
}
}
}
}
}