Add clearer exceptions, warnings and docs

This commit is contained in:
Bond_009 2019-10-20 21:12:03 +02:00
parent fdb0c3a1df
commit fef35d0505
10 changed files with 63 additions and 57 deletions

View File

@ -30,6 +30,9 @@ namespace Emby.Server.Implementations.Cryptography
private bool _disposed = false; private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="CryptographyProvider"/> class.
/// </summary>
public CryptographyProvider() public CryptographyProvider()
{ {
// FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto // FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto
@ -59,12 +62,6 @@ namespace Emby.Server.Implementations.Cryptography
throw new CryptographicException($"Cannot currently use PBKDF2 with requested hash method: {method}"); throw new CryptographicException($"Cannot currently use PBKDF2 with requested hash method: {method}");
} }
public byte[] ComputeHash(string hashMethod, byte[] bytes)
=> ComputeHash(hashMethod, bytes, Array.Empty<byte>());
public byte[] ComputeHashWithDefaultMethod(byte[] bytes)
=> ComputeHash(DefaultHashMethod, bytes);
public byte[] ComputeHash(string hashMethod, byte[] bytes, byte[] salt) public byte[] ComputeHash(string hashMethod, byte[] bytes, byte[] salt)
{ {
if (hashMethod == DefaultHashMethod) if (hashMethod == DefaultHashMethod)
@ -90,7 +87,6 @@ namespace Emby.Server.Implementations.Cryptography
} }
throw new CryptographicException($"Requested hash method is not supported: {hashMethod}"); throw new CryptographicException($"Requested hash method is not supported: {hashMethod}");
} }
public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt) public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt)

View File

@ -59,7 +59,10 @@ namespace Emby.Server.Implementations.Library
if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id) if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id)
|| _cryptographyProvider.DefaultHashMethod == readyHash.Id) || _cryptographyProvider.DefaultHashMethod == readyHash.Id)
{ {
byte[] calculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes, readyHash.Salt); byte[] calculatedHash = _cryptographyProvider.ComputeHash(
readyHash.Id,
passwordbytes,
readyHash.Salt);
if (calculatedHash.SequenceEqual(readyHash.Hash)) if (calculatedHash.SequenceEqual(readyHash.Hash))
{ {

View File

@ -179,12 +179,7 @@ namespace Emby.Server.Implementations.Library
_defaultPasswordResetProvider = passwordResetProviders.OfType<DefaultPasswordResetProvider>().First(); _defaultPasswordResetProvider = passwordResetProviders.OfType<DefaultPasswordResetProvider>().First();
} }
/// <summary> /// <inheritdoc />
/// Gets a User by Id.
/// </summary>
/// <param name="id">The id.</param>
/// <returns>User.</returns>
/// <exception cref="ArgumentException"></exception>
public User GetUserById(Guid id) public User GetUserById(Guid id)
{ {
if (id == Guid.Empty) if (id == Guid.Empty)
@ -196,11 +191,7 @@ namespace Emby.Server.Implementations.Library
return user; return user;
} }
/// <summary> /// <inheritdoc />
/// Gets the user by identifier.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>User.</returns>
public User GetUserById(string id) public User GetUserById(string id)
=> GetUserById(new Guid(id)); => GetUserById(new Guid(id));
@ -428,7 +419,6 @@ namespace Emby.Server.Implementations.Library
{ {
try try
{ {
var authenticationResult = provider is IRequiresResolvedUser requiresResolvedUser var authenticationResult = provider is IRequiresResolvedUser requiresResolvedUser
? await requiresResolvedUser.Authenticate(username, password, resolvedUser).ConfigureAwait(false) ? await requiresResolvedUser.Authenticate(username, password, resolvedUser).ConfigureAwait(false)
: await provider.Authenticate(username, password).ConfigureAwait(false); : await provider.Authenticate(username, password).ConfigureAwait(false);
@ -538,6 +528,8 @@ namespace Emby.Server.Implementations.Library
defaultName = "MyJellyfinUser"; defaultName = "MyJellyfinUser";
} }
_logger.LogWarning("No users, creating one with username {UserName}", defaultName);
var name = MakeValidUsername(defaultName); var name = MakeValidUsername(defaultName);
var user = InstantiateNewUser(name); var user = InstantiateNewUser(name);
@ -601,7 +593,7 @@ namespace Emby.Server.Implementations.Library
catch (Exception ex) catch (Exception ex)
{ {
// Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions
_logger.LogError(ex, "Error generating PrimaryImageAspectRatio for {user}", user.Name); _logger.LogError(ex, "Error generating PrimaryImageAspectRatio for {User}", user.Name);
} }
} }
@ -625,7 +617,7 @@ namespace Emby.Server.Implementations.Library
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Error getting {imageType} image info for {imagePath}", image.Type, image.Path); _logger.LogError(ex, "Error getting {ImageType} image info for {ImagePath}", image.Type, image.Path);
return null; return null;
} }
} }

View File

@ -42,6 +42,11 @@ namespace Emby.Server.Implementations.Library
{ {
var user = _userManager.GetUserById(query.UserId); var user = _userManager.GetUserById(query.UserId);
if (user == null)
{
throw new ArgumentException("User Id does not exists.", nameof(query));
}
var folders = _libraryManager.GetUserRootFolder() var folders = _libraryManager.GetUserRootFolder()
.GetChildren(user, true) .GetChildren(user, true)
.OfType<Folder>() .OfType<Folder>()
@ -54,7 +59,7 @@ namespace Emby.Server.Implementations.Library
foreach (var folder in folders) foreach (var folder in folders)
{ {
var collectionFolder = folder as ICollectionFolder; var collectionFolder = folder as ICollectionFolder;
var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType; var folderViewType = collectionFolder?.CollectionType;
if (UserView.IsUserSpecific(folder)) if (UserView.IsUserSpecific(folder))
{ {
@ -130,16 +135,11 @@ namespace Emby.Server.Implementations.Library
{ {
var index = orders.IndexOf(i.Id.ToString("N", CultureInfo.InvariantCulture)); var index = orders.IndexOf(i.Id.ToString("N", CultureInfo.InvariantCulture));
if (index == -1) if (index == -1
&& i is UserView view
&& view.DisplayParentId != Guid.Empty)
{ {
var view = i as UserView; index = orders.IndexOf(view.DisplayParentId.ToString("N", CultureInfo.InvariantCulture));
if (view != null)
{
if (!view.DisplayParentId.Equals(Guid.Empty))
{
index = orders.IndexOf(view.DisplayParentId.ToString("N", CultureInfo.InvariantCulture));
}
}
} }
return index == -1 ? int.MaxValue : index; return index == -1 ? int.MaxValue : index;

View File

@ -1388,27 +1388,28 @@ namespace Emby.Server.Implementations.Session
if (user != null) if (user != null)
{ {
// TODO: Move this to userManager? // TODO: Move this to userManager?
if (!string.IsNullOrEmpty(request.DeviceId)) if (!string.IsNullOrEmpty(request.DeviceId)
&& !_deviceManager.CanAccessDevice(user, request.DeviceId))
{ {
if (!_deviceManager.CanAccessDevice(user, request.DeviceId)) throw new SecurityException("User is not allowed access from this device.");
{
throw new SecurityException("User is not allowed access from this device.");
}
} }
} }
if (enforcePassword) if (enforcePassword)
{ {
var result = await _userManager.AuthenticateUser(request.Username, request.Password, request.PasswordSha1, request.RemoteEndPoint, true).ConfigureAwait(false); user = await _userManager.AuthenticateUser(
request.Username,
request.Password,
request.PasswordSha1,
request.RemoteEndPoint,
true).ConfigureAwait(false);
}
if (result == null) if (user == null)
{ {
AuthenticationFailed?.Invoke(this, new GenericEventArgs<AuthenticationRequest>(request)); AuthenticationFailed?.Invoke(this, new GenericEventArgs<AuthenticationRequest>(request));
throw new SecurityException("Invalid user or password entered."); throw new SecurityException("Invalid user or password entered.");
}
user = result;
} }
var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName); var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName);

View File

@ -10,6 +10,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Library; using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Api.UserLibrary namespace MediaBrowser.Api.UserLibrary
{ {
@ -49,7 +50,12 @@ namespace MediaBrowser.Api.UserLibrary
private readonly IAuthorizationContext _authContext; private readonly IAuthorizationContext _authContext;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
public UserViewsService(IUserManager userManager, IUserViewManager userViewManager, IDtoService dtoService, IAuthorizationContext authContext, ILibraryManager libraryManager) public UserViewsService(
IUserManager userManager,
IUserViewManager userViewManager,
IDtoService dtoService,
IAuthorizationContext authContext,
ILibraryManager libraryManager)
{ {
_userManager = userManager; _userManager = userManager;
_userViewManager = userViewManager; _userViewManager = userViewManager;

View File

@ -61,13 +61,13 @@ namespace MediaBrowser.Common.Cryptography
/// <value>Return the hashed password.</value> /// <value>Return the hashed password.</value>
public byte[] Hash { get; } public byte[] Hash { get; }
public static PasswordHash Parse(string storageString) public static PasswordHash Parse(string hashString)
{ {
string[] splitted = storageString.Split('$'); string[] splitted = hashString.Split('$');
// The string should at least contain the hash function and the hash itself // The string should at least contain the hash function and the hash itself
if (splitted.Length < 3) if (splitted.Length < 3)
{ {
throw new ArgumentException("String doesn't contain enough segments", nameof(storageString)); throw new ArgumentException("String doesn't contain enough segments", nameof(hashString));
} }
// Start at 1, the first index shouldn't contain any data // Start at 1, the first index shouldn't contain any data

View File

@ -1152,6 +1152,11 @@ namespace MediaBrowser.Controller.Entities
public List<BaseItem> GetChildren(User user, bool includeLinkedChildren) public List<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{ {
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
return GetChildren(user, includeLinkedChildren, null); return GetChildren(user, includeLinkedChildren, null);
} }
@ -1163,7 +1168,10 @@ namespace MediaBrowser.Controller.Entities
} }
//the true root should return our users root folder children //the true root should return our users root folder children
if (IsPhysicalRoot) return LibraryManager.GetUserRootFolder().GetChildren(user, includeLinkedChildren); if (IsPhysicalRoot)
{
return LibraryManager.GetUserRootFolder().GetChildren(user, includeLinkedChildren);
}
var result = new Dictionary<Guid, BaseItem>(); var result = new Dictionary<Guid, BaseItem>();

View File

@ -39,17 +39,21 @@ namespace MediaBrowser.Controller.Library
event EventHandler<GenericEventArgs<User>> UserDeleted; event EventHandler<GenericEventArgs<User>> UserDeleted;
event EventHandler<GenericEventArgs<User>> UserCreated; event EventHandler<GenericEventArgs<User>> UserCreated;
event EventHandler<GenericEventArgs<User>> UserPolicyUpdated; event EventHandler<GenericEventArgs<User>> UserPolicyUpdated;
event EventHandler<GenericEventArgs<User>> UserConfigurationUpdated; event EventHandler<GenericEventArgs<User>> UserConfigurationUpdated;
event EventHandler<GenericEventArgs<User>> UserPasswordChanged; event EventHandler<GenericEventArgs<User>> UserPasswordChanged;
event EventHandler<GenericEventArgs<User>> UserLockedOut; event EventHandler<GenericEventArgs<User>> UserLockedOut;
/// <summary> /// <summary>
/// Gets a User by Id /// Gets a User by Id.
/// </summary> /// </summary>
/// <param name="id">The id.</param> /// <param name="id">The id.</param>
/// <returns>User.</returns> /// <returns>The user with the specified Id, or <c>null</c> id the user doesn't exist.</returns>
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentException"><c>id</c> is an empty Guid.</exception>
User GetUserById(Guid id); User GetUserById(Guid id);
/// <summary> /// <summary>

View File

@ -8,10 +8,6 @@ namespace MediaBrowser.Model.Cryptography
IEnumerable<string> GetSupportedHashMethods(); IEnumerable<string> GetSupportedHashMethods();
byte[] ComputeHash(string HashMethod, byte[] bytes);
byte[] ComputeHashWithDefaultMethod(byte[] bytes);
byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt); byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt);
byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt); byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt);