From 84f22dbadce3881de7f4a50b0cc0732e2a6d9b10 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 #3089 --- .../AuthenticationRequiredModalContent.js | 15 +++++++++- .../src/Settings/General/SecuritySettings.js | 16 ++++++++++ src/NzbDrone.Core/Localization/Core/en.json | 2 ++ .../Validation/Paths/FileExistsValidator.cs | 2 +- .../Config/HostConfigController.cs | 29 +++++++++++++++---- .../Config/HostConfigResource.cs | 1 + 6 files changed, 58 insertions(+), 7 deletions(-) diff --git a/frontend/src/FirstRun/AuthenticationRequiredModalContent.js b/frontend/src/FirstRun/AuthenticationRequiredModalContent.js index 71915f701..41cd6f550 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 a743e953b..8e2597741 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; @@ -193,6 +194,21 @@ class SecuritySettings extends Component { null } + { + authenticationEnabled ? + + {translate('PasswordConfirmation')} + + + : + null + } + {translate('ApiKey')} diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 2bb241c61..daca8f586 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -58,6 +58,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.", @@ -690,6 +691,7 @@ "PageSize": "Page Size", "PageSizeHelpText": "Number of items to show on each page", "Password": "Password", + "PasswordConfirmation": "Password Confirmation", "PasswordHelpText": "Calibre content server password", "PastDays": "Past Days", "PastDaysHelpText": "Days for iCal feed to look into the past", 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 diff --git a/src/Readarr.Api.V1/Config/HostConfigController.cs b/src/Readarr.Api.V1/Config/HostConfigController.cs index 57a5875a0..85792f8f3 100644 --- a/src/Readarr.Api.V1/Config/HostConfigController.cs +++ b/src/Readarr.Api.V1/Config/HostConfigController.cs @@ -47,6 +47,9 @@ namespace Readarr.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 Readarr.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; + } + protected override HostConfigResource GetResourceById(int id) { return GetHostConfig(); @@ -93,11 +113,10 @@ namespace Readarr.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/Readarr.Api.V1/Config/HostConfigResource.cs b/src/Readarr.Api.V1/Config/HostConfigResource.cs index ecd4b8ee0..04fad5ad9 100644 --- a/src/Readarr.Api.V1/Config/HostConfigResource.cs +++ b/src/Readarr.Api.V1/Config/HostConfigResource.cs @@ -19,6 +19,7 @@ namespace Readarr.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; }