Added configuration validation for content and request handler settings.
This commit is contained in:
@@ -4,12 +4,25 @@ namespace Umbraco.Core.Configuration.Models
|
||||
{
|
||||
public class ContentErrorPage
|
||||
{
|
||||
//TODO introduce validation, to check only one of key/id/xPath is used.
|
||||
public int ContentId { get; }
|
||||
public Guid ContentKey { get; }
|
||||
public string ContentXPath { get; }
|
||||
public bool HasContentId { get; }
|
||||
public bool HasContentKey { get; }
|
||||
public int ContentId { get; set; }
|
||||
|
||||
public Guid ContentKey { get; set; }
|
||||
|
||||
public string ContentXPath { get; set; }
|
||||
|
||||
public bool HasContentId => ContentId != 0;
|
||||
|
||||
public bool HasContentKey => ContentKey != Guid.Empty;
|
||||
|
||||
public bool HasContentXPath => !string.IsNullOrEmpty(ContentXPath);
|
||||
|
||||
public string Culture { get; set; }
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
// Entry is valid if Culture and one and only one of ContentId, ContentKey or ContentXPath is provided.
|
||||
return !string.IsNullOrWhiteSpace(Culture) &&
|
||||
((HasContentId ? 1 : 0) + (HasContentKey ? 1 : 0) + (HasContentXPath ? 1 : 0) == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,13 @@ namespace Umbraco.Core.Configuration.Models
|
||||
private class ImagingAutoFillUploadField : IImagingAutoFillUploadField
|
||||
{
|
||||
public string Alias { get; set; }
|
||||
|
||||
public string WidthFieldAlias { get; set; }
|
||||
|
||||
public string HeightFieldAlias { get; set; }
|
||||
|
||||
public string LengthFieldAlias { get; set; }
|
||||
|
||||
public string ExtensionFieldAlias { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Macros;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models
|
||||
@@ -16,11 +15,21 @@ namespace Umbraco.Core.Configuration.Models
|
||||
|
||||
public bool ResolveUrlsFromTextString { get; set; } = false;
|
||||
|
||||
public IEnumerable<ContentErrorPage> Error404Collection { get; set; } = Array.Empty<ContentErrorPage>();
|
||||
public ContentErrorPage[] Error404Collection { get; set; } = Array.Empty<ContentErrorPage>();
|
||||
|
||||
public string PreviewBadge { get; set; } = DefaultPreviewBadge;
|
||||
|
||||
public MacroErrorBehaviour MacroErrors { get; set; } = MacroErrorBehaviour.Inline;
|
||||
public string MacroErrors { get; set; } = MacroErrorBehaviour.Inline.ToString();
|
||||
|
||||
public MacroErrorBehaviour MacroErrorsBehaviour
|
||||
{
|
||||
get
|
||||
{
|
||||
return Enum.TryParse<MacroErrorBehaviour>(MacroErrors, true, out var value)
|
||||
? value
|
||||
: MacroErrorBehaviour.Inline;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> DisallowedUploadFiles { get; set; } = new[] { "ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd" };
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models.Validation
|
||||
{
|
||||
public abstract class ConfigurationValidationBase
|
||||
{
|
||||
public bool ValidateStringIsOneOfValidValues(string configPath, string value, IEnumerable<string> validValues, out string message)
|
||||
{
|
||||
if (!validValues.InvariantContains(value))
|
||||
{
|
||||
message = $"Configuration entry {configPath} contains an invalid value '{value}', it should be one of the following: '{string.Join(", ", validValues)}'.";
|
||||
return false;
|
||||
}
|
||||
|
||||
message = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ValidateStringIsOneOfEnumValues(string configPath, string value, Type enumType, out string message)
|
||||
{
|
||||
var validValues = Enum.GetValues(enumType).OfType<object>().Select(x => x.ToString().ToFirstLowerInvariant());
|
||||
return ValidateStringIsOneOfValidValues(configPath, value, validValues, out message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core.Macros;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models.Validation
|
||||
{
|
||||
public class ContentSettingsValidation : ConfigurationValidationBase, IValidateOptions<ContentSettings>
|
||||
{
|
||||
public ValidateOptionsResult Validate(string name, ContentSettings options)
|
||||
{
|
||||
string message;
|
||||
if (!ValidateMacroErrors(options.MacroErrors, out message))
|
||||
{
|
||||
return ValidateOptionsResult.Fail(message);
|
||||
}
|
||||
|
||||
if (!ValidateError404Collection(options.Error404Collection, out message))
|
||||
{
|
||||
return ValidateOptionsResult.Fail(message);
|
||||
}
|
||||
|
||||
return ValidateOptionsResult.Success;
|
||||
}
|
||||
|
||||
private bool ValidateMacroErrors(string value, out string message)
|
||||
{
|
||||
return ValidateStringIsOneOfEnumValues("Content:MacroErrors", value, typeof(MacroErrorBehaviour), out message);
|
||||
}
|
||||
|
||||
private bool ValidateError404Collection(IEnumerable<ContentErrorPage> values, out string message)
|
||||
{
|
||||
if (values.Any(x => !x.IsValid()))
|
||||
{
|
||||
message = $"Configuration entry Content:Error404Collection contains one or more invalid values. Culture and one and only one of ContentId, ContentKey and ContentXPath must be specified for each entry.";
|
||||
return false;
|
||||
}
|
||||
|
||||
message = string.Empty;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models.Validation
|
||||
{
|
||||
public class RequestHandlerSettingsValidation : ConfigurationValidationBase, IValidateOptions<RequestHandlerSettings>
|
||||
{
|
||||
public ValidateOptionsResult Validate(string name, RequestHandlerSettings options)
|
||||
{
|
||||
if (!ValidateConvertUrlsToAscii(options.ConvertUrlsToAscii, out var message))
|
||||
{
|
||||
return ValidateOptionsResult.Fail(message);
|
||||
}
|
||||
|
||||
return ValidateOptionsResult.Success;
|
||||
}
|
||||
|
||||
private bool ValidateConvertUrlsToAscii(string value, out string message)
|
||||
{
|
||||
var validValues = new[] { "try", "true", "false" };
|
||||
return ValidateStringIsOneOfValidValues("RequestHandler:ConvertUrlsToAscii", value, validValues, out message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Web.Routing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the content id based on the configured IContentErrorPage section
|
||||
/// Returns the content id based on the configured ContentErrorPage section.
|
||||
/// </summary>
|
||||
/// <param name="errorPage"></param>
|
||||
/// <param name="entityService"></param>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Tests.Common.Builders;
|
||||
|
||||
@@ -18,6 +18,7 @@ using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.Configuration.Models.Validation;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Logging.Serilog;
|
||||
@@ -126,6 +127,9 @@ namespace Umbraco.Extensions
|
||||
{
|
||||
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
|
||||
|
||||
services.AddSingleton<IValidateOptions<ContentSettings>, ContentSettingsValidation>();
|
||||
services.AddSingleton<IValidateOptions<RequestHandlerSettings>, RequestHandlerSettingsValidation>();
|
||||
|
||||
services.Configure<ActiveDirectorySettings>(configuration.GetSection(Constants.Configuration.ConfigPrefix + "ActiveDirectory"));
|
||||
services.Configure<ConnectionStrings>(configuration.GetSection("ConnectionStrings"), o => o.BindNonPublicProperties = true);
|
||||
services.Configure<ContentSettings>(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Content"));
|
||||
@@ -149,7 +153,6 @@ namespace Umbraco.Extensions
|
||||
services.Configure<UserPasswordConfigurationSettings>(configuration.GetSection(Constants.Configuration.ConfigSecurityPrefix + "UserPassword"));
|
||||
services.Configure<WebRoutingSettings>(configuration.GetSection(Constants.Configuration.ConfigPrefix + "WebRouting"));
|
||||
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ namespace Umbraco.Web.Macros
|
||||
Alias = macro.Alias,
|
||||
MacroSource = macro.MacroSource,
|
||||
Exception = e,
|
||||
Behaviour = _contentSettings.MacroErrors
|
||||
Behaviour = _contentSettings.MacroErrorsBehaviour
|
||||
};
|
||||
|
||||
switch (macroErrorEventArgs.Behaviour)
|
||||
|
||||
@@ -290,7 +290,7 @@ namespace Umbraco.Web.Macros
|
||||
Alias = macro.Alias,
|
||||
MacroSource = macro.MacroSource,
|
||||
Exception = e,
|
||||
Behaviour = _contentSettings.MacroErrors
|
||||
Behaviour = _contentSettings.MacroErrorsBehaviour
|
||||
};
|
||||
|
||||
switch (macroErrorEventArgs.Behaviour)
|
||||
|
||||
Reference in New Issue
Block a user