diff --git a/src/Lidarr.Api.V1/Config/CertificateValidator.cs b/src/Lidarr.Api.V1/Config/CertificateValidator.cs new file mode 100644 index 000000000..5dee51e89 --- /dev/null +++ b/src/Lidarr.Api.V1/Config/CertificateValidator.cs @@ -0,0 +1,52 @@ +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using FluentValidation; +using FluentValidation.Validators; +using NLog; +using NzbDrone.Common.Instrumentation; + +namespace Lidarr.Api.V1.Config +{ + public static class CertificateValidation + { + public static IRuleBuilderOptions IsValidCertificate(this IRuleBuilder ruleBuilder) + { + return ruleBuilder.SetValidator(new CertificateValidator()); + } + } + + public class CertificateValidator : PropertyValidator + { + protected override string GetDefaultMessageTemplate() => "Invalid SSL certificate file or password. {message}"; + + private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(CertificateValidator)); + + protected override bool IsValid(PropertyValidatorContext context) + { + if (context.PropertyValue == null) + { + return false; + } + + if (context.InstanceToValidate is not HostConfigResource resource) + { + return true; + } + + try + { + new X509Certificate2(resource.SslCertPath, resource.SslCertPassword, X509KeyStorageFlags.DefaultKeySet); + + return true; + } + catch (CryptographicException ex) + { + Logger.Debug(ex, "Invalid SSL certificate file or password. {0}", ex.Message); + + context.MessageFormatter.AppendArgument("message", ex.Message); + + return false; + } + } + } +} diff --git a/src/Lidarr.Api.V1/Config/HostConfigController.cs b/src/Lidarr.Api.V1/Config/HostConfigController.cs index ca3f88fc2..9046943e8 100644 --- a/src/Lidarr.Api.V1/Config/HostConfigController.cs +++ b/src/Lidarr.Api.V1/Config/HostConfigController.cs @@ -1,7 +1,6 @@ using System.IO; using System.Linq; using System.Reflection; -using System.Security.Cryptography.X509Certificates; using FluentValidation; using Lidarr.Http; using Lidarr.Http.REST; @@ -58,7 +57,7 @@ namespace Lidarr.Api.V1.Config .NotEmpty() .IsValidPath() .SetValidator(fileExistsValidator) - .Must((resource, path) => IsValidSslCertificate(resource)).WithMessage("Invalid SSL certificate file or password") + .IsValidCertificate() .When(c => c.EnableSsl); SharedValidator.RuleFor(c => c.LogSizeLimit).InclusiveBetween(1, 10); @@ -71,21 +70,6 @@ namespace Lidarr.Api.V1.Config SharedValidator.RuleFor(c => c.BackupRetention).InclusiveBetween(1, 90); } - private bool IsValidSslCertificate(HostConfigResource resource) - { - X509Certificate2 cert; - try - { - cert = new X509Certificate2(resource.SslCertPath, resource.SslCertPassword, X509KeyStorageFlags.DefaultKeySet); - } - catch - { - return false; - } - - return cert != null; - } - private bool IsMatchingPassword(HostConfigResource resource) { var user = _userService.FindUser();