diff --git a/frontend/src/FirstRun/AuthenticationRequiredModalContent.js b/frontend/src/FirstRun/AuthenticationRequiredModalContent.js
index 426d573a5..3c341c0c5 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 9986de3d9..5358c6107 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 7ad228a08..9f1173ad0 100644
--- a/src/NzbDrone.Core/Localization/Core/en.json
+++ b/src/NzbDrone.Core/Localization/Core/en.json
@@ -86,6 +86,7 @@
"AuthenticationRequired": "Authentication Required",
"AuthenticationRequiredHelpText": "Change which requests authentication is required for. Do not change unless you understand the risks.",
"AuthenticationRequiredPasswordHelpTextWarning": "Enter a new password",
+ "AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Confirm 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.",
"Auto": "Auto",
@@ -824,6 +825,7 @@
"ParseModalHelpTextDetails": "{appName} will attempt to parse the title and show you details about it",
"ParseModalUnableToParse": "Unable to parse the provided title, please try again.",
"Password": "Password",
+ "PasswordConfirmation": "Password Confirmation",
"Path": "Path",
"Paused": "Paused",
"Peers": "Peers",
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/Radarr.Api.V3/Config/HostConfigController.cs b/src/Radarr.Api.V3/Config/HostConfigController.cs
index 23fb54b60..086180b86 100644
--- a/src/Radarr.Api.V3/Config/HostConfigController.cs
+++ b/src/Radarr.Api.V3/Config/HostConfigController.cs
@@ -47,6 +47,9 @@ namespace Radarr.Api.V3.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 Radarr.Api.V3.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 Radarr.Api.V3.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/Radarr.Api.V3/Config/HostConfigResource.cs b/src/Radarr.Api.V3/Config/HostConfigResource.cs
index 7d4aed6f3..1edae531f 100644
--- a/src/Radarr.Api.V3/Config/HostConfigResource.cs
+++ b/src/Radarr.Api.V3/Config/HostConfigResource.cs
@@ -19,6 +19,7 @@ namespace Radarr.Api.V3.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; }