From 1361492bf537ba86f7e6445bbccfce1e39f3fe81 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 18 Nov 2023 18:51:23 -0800 Subject: [PATCH] New: Require password confirmation when setting or changing password (cherry picked from commit b248163df598dc611ee919d525eb7357256d73d5) Closes #4315 --- .../AuthenticationRequiredModalContent.js | 15 +++++++++- .../src/Settings/General/SecuritySettings.js | 16 ++++++++++ .../Config/HostConfigController.cs | 29 +++++++++++++++---- .../Config/HostConfigResource.cs | 1 + src/NzbDrone.Core/Localization/Core/en.json | 2 ++ .../Validation/Paths/FileExistsValidator.cs | 2 +- 6 files changed, 58 insertions(+), 7 deletions(-) diff --git a/frontend/src/FirstRun/AuthenticationRequiredModalContent.js b/frontend/src/FirstRun/AuthenticationRequiredModalContent.js index 4ad2d1b09..5eb9c5cd5 100644 --- a/frontend/src/FirstRun/AuthenticationRequiredModalContent.js +++ b/frontend/src/FirstRun/AuthenticationRequiredModalContent.js @@ -34,7 +34,8 @@ function AuthenticationRequiredModalContent(props) { authenticationMethod, authenticationRequired, username, - password + password, + passwordConfirmation } = settings; const authenticationEnabled = authenticationMethod && authenticationMethod.value !== 'none'; @@ -120,6 +121,18 @@ function AuthenticationRequiredModalContent(props) { {...password} /> + + + {translate('PasswordConfirmation')} + + + : null } diff --git a/frontend/src/Settings/General/SecuritySettings.js b/frontend/src/Settings/General/SecuritySettings.js index 551a14a4e..ddaae339a 100644 --- a/frontend/src/Settings/General/SecuritySettings.js +++ b/frontend/src/Settings/General/SecuritySettings.js @@ -124,6 +124,7 @@ class SecuritySettings extends Component { authenticationRequired, username, password, + passwordConfirmation, apiKey, certificateValidation } = settings; @@ -199,6 +200,21 @@ class SecuritySettings extends Component { null } + { + authenticationEnabled ? + + {translate('PasswordConfirmation')} + + + : + null + } + {translate('APIKey')} diff --git a/src/Lidarr.Api.V1/Config/HostConfigController.cs b/src/Lidarr.Api.V1/Config/HostConfigController.cs index d60280300..3184a1a83 100644 --- a/src/Lidarr.Api.V1/Config/HostConfigController.cs +++ b/src/Lidarr.Api.V1/Config/HostConfigController.cs @@ -47,6 +47,9 @@ namespace Lidarr.Api.V1.Config SharedValidator.RuleFor(c => c.Password).NotEmpty().When(c => c.AuthenticationMethod == AuthenticationType.Basic || 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).NotEqual(c => c.Port).When(c => c.EnableSsl); @@ -81,6 +84,23 @@ namespace Lidarr.Api.V1.Config 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) { return GetHostConfig(); @@ -93,11 +113,10 @@ namespace Lidarr.Api.V1.Config resource.Id = 1; var user = _userService.FindUser(); - if (user != null) - { - resource.Username = user.Username; - resource.Password = user.Password; - } + + resource.Username = user?.Username ?? string.Empty; + resource.Password = user?.Password ?? string.Empty; + resource.PasswordConfirmation = string.Empty; return resource; } diff --git a/src/Lidarr.Api.V1/Config/HostConfigResource.cs b/src/Lidarr.Api.V1/Config/HostConfigResource.cs index abdf26c39..9182901cb 100644 --- a/src/Lidarr.Api.V1/Config/HostConfigResource.cs +++ b/src/Lidarr.Api.V1/Config/HostConfigResource.cs @@ -19,6 +19,7 @@ namespace Lidarr.Api.V1.Config public bool AnalyticsEnabled { get; set; } public string Username { get; set; } public string Password { get; set; } + public string PasswordConfirmation { get; set; } public string LogLevel { get; set; } public string ConsoleLogLevel { get; set; } public string Branch { get; set; } diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 679c07b00..ff3e449e7 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -125,6 +125,7 @@ "AuthenticationMethodHelpTextWarning": "Please select a valid authentication method", "AuthenticationRequired": "Authentication Required", "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", "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.", @@ -730,6 +731,7 @@ "PageSize": "Page Size", "PageSizeHelpText": "Number of items to show on each page", "Password": "Password", + "PasswordConfirmation": "Password Confirmation", "PastDays": "Past Days", "PastDaysHelpText": "Days for iCal feed to look into the past", "Path": "Path", diff --git a/src/NzbDrone.Core/Validation/Paths/FileExistsValidator.cs b/src/NzbDrone.Core/Validation/Paths/FileExistsValidator.cs index 5393ce57b..327765537 100644 --- a/src/NzbDrone.Core/Validation/Paths/FileExistsValidator.cs +++ b/src/NzbDrone.Core/Validation/Paths/FileExistsValidator.cs @@ -1,4 +1,4 @@ -using FluentValidation.Validators; +using FluentValidation.Validators; using NzbDrone.Common.Disk; namespace NzbDrone.Core.Validation.Paths