support in-home easy password

This commit is contained in:
Luke Pulverenti 2015-01-29 01:06:24 -05:00
parent 82fe244fa1
commit a6145e54d9
8 changed files with 165 additions and 28 deletions

View File

@ -11,7 +11,6 @@ using MediaBrowser.Model.Connect;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Users;
using ServiceStack;
using ServiceStack.Text.Controller;
using System;
using System.Collections.Generic;
using System.Linq;
@ -148,6 +147,32 @@ namespace MediaBrowser.Api
public bool ResetPassword { get; set; }
}
/// <summary>
/// Class UpdateUserEasyPassword
/// </summary>
[Route("/Users/{Id}/EasyPassword", "POST", Summary = "Updates a user's easy password")]
[Authenticated]
public class UpdateUserEasyPassword : IReturnVoid
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
public string Id { get; set; }
/// <summary>
/// Gets or sets the new password.
/// </summary>
/// <value>The new password.</value>
public string NewPassword { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [reset password].
/// </summary>
/// <value><c>true</c> if [reset password]; otherwise, <c>false</c>.</value>
public bool ResetPassword { get; set; }
}
/// <summary>
/// Class UpdateUser
/// </summary>
@ -410,6 +435,8 @@ namespace MediaBrowser.Api
public async Task PostAsync(UpdateUserPassword request)
{
AssertCanUpdateUser(request.Id);
var user = _userManager.GetUserById(request.Id);
if (user == null)
@ -434,6 +461,33 @@ namespace MediaBrowser.Api
}
}
public void Post(UpdateUserEasyPassword request)
{
var task = PostAsync(request);
Task.WaitAll(task);
}
public async Task PostAsync(UpdateUserEasyPassword request)
{
AssertCanUpdateUser(request.Id);
var user = _userManager.GetUserById(request.Id);
if (user == null)
{
throw new ResourceNotFoundException("User not found");
}
if (request.ResetPassword)
{
await _userManager.ResetEasyPassword(user).ConfigureAwait(false);
}
else
{
await _userManager.ChangeEasyPassword(user, request.NewPassword).ConfigureAwait(false);
}
}
/// <summary>
/// Posts the specified request.
/// </summary>
@ -449,7 +503,9 @@ namespace MediaBrowser.Api
{
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
var id = new Guid(GetPathValue(1));
var id = GetPathValue(1);
AssertCanUpdateUser(id);
var dtoUser = request;
@ -499,11 +555,29 @@ namespace MediaBrowser.Api
public void Post(UpdateUserConfiguration request)
{
AssertCanUpdateUser(request.Id);
var task = _userManager.UpdateConfiguration(request.Id, request);
Task.WaitAll(task);
}
private void AssertCanUpdateUser(string userId)
{
var auth = AuthorizationContext.GetAuthorizationInfo(Request);
// If they're going to update the record of another user, they must be an administrator
if (!string.Equals(userId, auth.UserId, StringComparison.OrdinalIgnoreCase))
{
var authenticatedUser = _userManager.GetUserById(auth.UserId);
if (!authenticatedUser.Policy.IsAdministrator)
{
throw new SecurityException("Unauthorized access.");
}
}
}
public void Post(UpdateUserPolicy request)
{
var task = UpdateUserPolicy(request);

View File

@ -50,7 +50,7 @@ namespace MediaBrowser.Common.Implementations.Networking
{
NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
}
@ -106,6 +106,11 @@ namespace MediaBrowser.Common.Implementations.Networking
// Private address space:
// http://en.wikipedia.org/wiki/Private_network
if (endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase))
{
return Is172AddressPrivate(endpoint);
}
return
// If url was requested with computer name, we may see this
@ -114,11 +119,23 @@ namespace MediaBrowser.Common.Implementations.Networking
endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) ||
endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
endpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) ||
endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) ||
endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase) ||
endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase);
}
private bool Is172AddressPrivate(string endpoint)
{
for (var i = 16; i <= 31; i++)
{
if (endpoint.StartsWith("172." + i.ToString(CultureInfo.InvariantCulture) + ".", StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
public bool IsInLocalNetwork(string endpoint)
{
return IsInLocalNetworkInternal(endpoint, true);
@ -175,7 +192,7 @@ namespace MediaBrowser.Common.Implementations.Networking
return false;
}
public IEnumerable<IPAddress> GetIpAddresses(string hostName)
{
return Dns.GetHostAddresses(hostName);

View File

@ -32,7 +32,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value>The password.</value>
public string Password { get; set; }
public string LocalPassword { get; set; }
public string EasyPassword { get; set; }
public string ConnectUserName { get; set; }
public string ConnectUserId { get; set; }

View File

@ -117,6 +117,13 @@ namespace MediaBrowser.Controller.Library
/// <returns>Task.</returns>
Task ResetPassword(User user);
/// <summary>
/// Resets the easy password.
/// </summary>
/// <param name="user">The user.</param>
/// <returns>Task.</returns>
Task ResetEasyPassword(User user);
/// <summary>
/// Changes the password.
/// </summary>
@ -125,6 +132,14 @@ namespace MediaBrowser.Controller.Library
/// <returns>Task.</returns>
Task ChangePassword(User user, string newPasswordSha1);
/// <summary>
/// Changes the easy password.
/// </summary>
/// <param name="user">The user.</param>
/// <param name="newPasswordSha1">The new password sha1.</param>
/// <returns>Task.</returns>
Task ChangeEasyPassword(User user, string newPasswordSha1);
/// <summary>
/// Gets the user dto.
/// </summary>

View File

@ -66,6 +66,12 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value><c>true</c> if this instance has configured password; otherwise, <c>false</c>.</value>
public bool HasConfiguredPassword { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has configured easy password.
/// </summary>
/// <value><c>true</c> if this instance has configured easy password; otherwise, <c>false</c>.</value>
public bool HasConfiguredEasyPassword { get; set; }
/// <summary>
/// Gets or sets the last login date.

View File

@ -275,9 +275,9 @@ namespace MediaBrowser.Server.Implementations.Library
private string GetLocalPasswordHash(User user)
{
return string.IsNullOrEmpty(user.LocalPassword)
return string.IsNullOrEmpty(user.EasyPassword)
? GetSha1String(string.Empty)
: user.LocalPassword;
: user.EasyPassword;
}
private bool IsPasswordEmpty(string passwordHash)
@ -355,18 +355,20 @@ namespace MediaBrowser.Server.Implementations.Library
var passwordHash = GetPasswordHash(user);
var hasConfiguredDefaultPassword = !IsPasswordEmpty(passwordHash);
var hasConfiguredPassword = !IsPasswordEmpty(passwordHash);
var hasConfiguredEasyPassword = !IsPasswordEmpty(GetLocalPasswordHash(user));
var hasPassword = user.Configuration.EnableLocalPassword && !string.IsNullOrEmpty(remoteEndPoint) && _networkManager.IsInLocalNetwork(remoteEndPoint) ?
!IsPasswordEmpty(GetLocalPasswordHash(user)) :
hasConfiguredDefaultPassword;
hasConfiguredEasyPassword :
hasConfiguredPassword;
var dto = new UserDto
{
Id = user.Id.ToString("N"),
Name = user.Name,
HasPassword = hasPassword,
HasConfiguredPassword = hasConfiguredDefaultPassword,
HasConfiguredPassword = hasConfiguredPassword,
HasConfiguredEasyPassword = hasConfiguredEasyPassword,
LastActivityDate = user.LastActivityDate,
LastLoginDate = user.LastLoginDate,
Configuration = user.Configuration,
@ -613,18 +615,11 @@ namespace MediaBrowser.Server.Implementations.Library
return ChangePassword(user, GetSha1String(string.Empty));
}
/// <summary>
/// Changes the password.
/// </summary>
/// <param name="user">The user.</param>
/// <param name="newPasswordSha1">The new password sha1.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">
/// user
/// or
/// newPassword
/// </exception>
/// <exception cref="System.ArgumentException">Passwords for guests cannot be changed.</exception>
public Task ResetEasyPassword(User user)
{
return ChangeEasyPassword(user, GetSha1String(string.Empty));
}
public async Task ChangePassword(User user, string newPasswordSha1)
{
if (user == null)
@ -648,6 +643,29 @@ namespace MediaBrowser.Server.Implementations.Library
EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger);
}
public async Task ChangeEasyPassword(User user, string newPasswordSha1)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
if (string.IsNullOrWhiteSpace(newPasswordSha1))
{
throw new ArgumentNullException("newPasswordSha1");
}
if (user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest)
{
throw new ArgumentException("Passwords for guests cannot be changed.");
}
user.EasyPassword = newPasswordSha1;
await UpdateUser(user).ConfigureAwait(false);
EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger);
}
/// <summary>
/// Instantiates the new user.
/// </summary>

View File

@ -14,9 +14,12 @@
"FileReadError": "An error occurred while reading the file.",
"DeleteUser": "Delete User",
"DeleteUserConfirmation": "Are you sure you wish to delete this user?",
"PasswordResetHeader": "Password Reset",
"PasswordResetHeader": "Reset Password",
"PasswordResetComplete": "The password has been reset.",
"PinCodeResetComplete": "The pin code has been reset.",
"PasswordResetConfirmation": "Are you sure you wish to reset the password?",
"PinCodeResetConfirmation": "Are you sure you wish to reset the pin code?",
"HeaderPinCodeReset": "Reset Pin Code",
"PasswordSaved": "Password saved.",
"PasswordMatchError": "Password and password confirmation must match.",
"OptionRelease": "Official Release",

View File

@ -56,6 +56,7 @@
"HeaderVideo": "Video",
"HeaderPaths": "Paths",
"CategorySync": "Sync",
"HeaderEasyPinCode": "Easy Pin Code",
"RegisterWithPayPal": "Register with PayPal",
"HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
"HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@ -1132,11 +1133,14 @@
"LabelDisplayFoldersView": "Display a folders view to show plain media folders",
"ViewTypeLiveTvRecordingGroups": "Recordings",
"ViewTypeLiveTvChannels": "Channels",
"LabelAllowLocalAccessWithoutPassword": "Allow local access without a password",
"LabelAllowLocalAccessWithoutPasswordHelp": "When enabled, a password will not be required when signing in from within your home network.",
"LabelEasyPinCode": "Easy pin code:",
"EasyPasswordHelp": "Your easy pin code is used for offline access with supported Media Browser apps, and can also be used for easy in-network sign in.",
"LabelInNetworkSignInWithEasyPassword": "Enable in-network sign in with my easy pin code",
"LabelInNetworkSignInWithEasyPasswordHelp": "If enabled, you'll be able to use your easy pin code to sign in to Media Browser apps from inside your home network. Your regular password will only be needed away from home. If the pin code is left blank, you won't need a password within your home network.",
"HeaderPassword": "Password",
"HeaderLocalAccess": "Local Access",
"HeaderViewOrder": "View Order",
"ButtonResetEasyPassword": "Reset easy pin code",
"LabelSelectUserViewOrder": "Choose the order your views will be displayed in within Media Browser apps",
"LabelMetadataRefreshMode": "Metadata refresh mode:",
"LabelImageRefreshMode": "Image refresh mode:",