New: Require password confirmation when setting or changing password

(cherry picked from commit b248163df598dc611ee919d525eb7357256d73d5)

Closes #4315
pull/4321/head
Mark McDowall 6 months ago committed by Bogdan
parent 8c1ac91342
commit 1361492bf5

@ -34,7 +34,8 @@ function AuthenticationRequiredModalContent(props) {
authenticationMethod, authenticationMethod,
authenticationRequired, authenticationRequired,
username, username,
password password,
passwordConfirmation
} = settings; } = settings;
const authenticationEnabled = authenticationMethod && authenticationMethod.value !== 'none'; const authenticationEnabled = authenticationMethod && authenticationMethod.value !== 'none';
@ -120,6 +121,18 @@ function AuthenticationRequiredModalContent(props) {
{...password} {...password}
/> />
</FormGroup> </FormGroup>
<FormGroup>
<FormLabel>{translate('PasswordConfirmation')}</FormLabel>
<FormInputGroup
type={inputTypes.PASSWORD}
name="passwordConfirmation"
onChange={onInputChange}
helpTextWarning={passwordConfirmation?.value ? undefined : translate('AuthenticationRequiredPasswordConfirmationHelpTextWarning')}
{...passwordConfirmation}
/>
</FormGroup>
</div> : </div> :
null null
} }

@ -124,6 +124,7 @@ class SecuritySettings extends Component {
authenticationRequired, authenticationRequired,
username, username,
password, password,
passwordConfirmation,
apiKey, apiKey,
certificateValidation certificateValidation
} = settings; } = settings;
@ -199,6 +200,21 @@ class SecuritySettings extends Component {
null null
} }
{
authenticationEnabled ?
<FormGroup>
<FormLabel>{translate('PasswordConfirmation')}</FormLabel>
<FormInputGroup
type={inputTypes.PASSWORD}
name="passwordConfirmation"
onChange={onInputChange}
{...passwordConfirmation}
/>
</FormGroup> :
null
}
<FormGroup> <FormGroup>
<FormLabel> <FormLabel>
{translate('APIKey')} {translate('APIKey')}

@ -47,6 +47,9 @@ namespace Lidarr.Api.V1.Config
SharedValidator.RuleFor(c => c.Password).NotEmpty().When(c => c.AuthenticationMethod == AuthenticationType.Basic || SharedValidator.RuleFor(c => c.Password).NotEmpty().When(c => c.AuthenticationMethod == AuthenticationType.Basic ||
c.AuthenticationMethod == AuthenticationType.Forms); c.AuthenticationMethod == AuthenticationType.Forms);
SharedValidator.RuleFor(c => c.PasswordConfirmation)
.Must((resource, p) => IsMatchingPassword(resource)).WithMessage("Must match Password");
SharedValidator.RuleFor(c => c.SslPort).ValidPort().When(c => c.EnableSsl); SharedValidator.RuleFor(c => c.SslPort).ValidPort().When(c => c.EnableSsl);
SharedValidator.RuleFor(c => c.SslPort).NotEqual(c => c.Port).When(c => c.EnableSsl); SharedValidator.RuleFor(c => c.SslPort).NotEqual(c => c.Port).When(c => c.EnableSsl);
@ -81,6 +84,23 @@ namespace Lidarr.Api.V1.Config
return cert != null; return cert != null;
} }
private bool IsMatchingPassword(HostConfigResource resource)
{
var user = _userService.FindUser();
if (user != null && user.Password == resource.Password)
{
return true;
}
if (resource.Password == resource.PasswordConfirmation)
{
return true;
}
return false;
}
public override HostConfigResource GetResourceById(int id) public override HostConfigResource GetResourceById(int id)
{ {
return GetHostConfig(); return GetHostConfig();
@ -93,11 +113,10 @@ namespace Lidarr.Api.V1.Config
resource.Id = 1; resource.Id = 1;
var user = _userService.FindUser(); var user = _userService.FindUser();
if (user != null)
{ resource.Username = user?.Username ?? string.Empty;
resource.Username = user.Username; resource.Password = user?.Password ?? string.Empty;
resource.Password = user.Password; resource.PasswordConfirmation = string.Empty;
}
return resource; return resource;
} }

@ -19,6 +19,7 @@ namespace Lidarr.Api.V1.Config
public bool AnalyticsEnabled { get; set; } public bool AnalyticsEnabled { get; set; }
public string Username { get; set; } public string Username { get; set; }
public string Password { get; set; } public string Password { get; set; }
public string PasswordConfirmation { get; set; }
public string LogLevel { get; set; } public string LogLevel { get; set; }
public string ConsoleLogLevel { get; set; } public string ConsoleLogLevel { get; set; }
public string Branch { get; set; } public string Branch { get; set; }

@ -125,6 +125,7 @@
"AuthenticationMethodHelpTextWarning": "Please select a valid authentication method", "AuthenticationMethodHelpTextWarning": "Please select a valid authentication method",
"AuthenticationRequired": "Authentication Required", "AuthenticationRequired": "Authentication Required",
"AuthenticationRequiredHelpText": "Change which requests authentication is required for. Do not change unless you understand the risks.", "AuthenticationRequiredHelpText": "Change which requests authentication is required for. Do not change unless you understand the risks.",
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Confirm new password",
"AuthenticationRequiredPasswordHelpTextWarning": "Enter a new password", "AuthenticationRequiredPasswordHelpTextWarning": "Enter a new password",
"AuthenticationRequiredUsernameHelpTextWarning": "Enter a new username", "AuthenticationRequiredUsernameHelpTextWarning": "Enter a new username",
"AuthenticationRequiredWarning": "To prevent remote access without authentication, {appName} now requires authentication to be enabled. You can optionally disable authentication from local addresses.", "AuthenticationRequiredWarning": "To prevent remote access without authentication, {appName} now requires authentication to be enabled. You can optionally disable authentication from local addresses.",
@ -730,6 +731,7 @@
"PageSize": "Page Size", "PageSize": "Page Size",
"PageSizeHelpText": "Number of items to show on each page", "PageSizeHelpText": "Number of items to show on each page",
"Password": "Password", "Password": "Password",
"PasswordConfirmation": "Password Confirmation",
"PastDays": "Past Days", "PastDays": "Past Days",
"PastDaysHelpText": "Days for iCal feed to look into the past", "PastDaysHelpText": "Days for iCal feed to look into the past",
"Path": "Path", "Path": "Path",

@ -1,4 +1,4 @@
using FluentValidation.Validators; using FluentValidation.Validators;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
namespace NzbDrone.Core.Validation.Paths namespace NzbDrone.Core.Validation.Paths

Loading…
Cancel
Save