Refactor setting arrays to sets (#16058)

Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
Ronald Barendse
2024-12-02 15:50:23 +01:00
committed by GitHub
parent 303758d1b2
commit 0d1cdd1bb4
23 changed files with 107 additions and 98 deletions

View File

@@ -20,6 +20,7 @@
<WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
</PropertyGroup>
<PropertyGroup>
<!--
TODO: Fix and remove overrides:

View File

@@ -91,7 +91,7 @@ internal sealed class InitializeMemberApplicationNotificationHandler : INotifica
}
}
private bool ValidateRedirectUrls(Uri[] redirectUrls)
private bool ValidateRedirectUrls(IEnumerable<Uri> redirectUrls)
{
if (redirectUrls.Any() is false)
{

View File

@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
@@ -82,6 +82,5 @@ public class GetHelpController : HelpControllerBase
return Ok(PagedViewModel<HelpPageResponseModel>.Empty());
}
private bool IsAllowedUrl(string? url) =>
_helpPageSettings.HelpPageUrlAllowList is null || _helpPageSettings.HelpPageUrlAllowList.Contains(url);
private bool IsAllowedUrl(string? url) => url is null || _helpPageSettings.HelpPageUrlAllowList.Contains(url);
}

View File

@@ -1,4 +1,4 @@
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Management.ViewModels.TemporaryFile;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Media;
@@ -22,8 +22,8 @@ public class TemporaryFileConfigurationPresentationFactory : ITemporaryFileConfi
new()
{
ImageFileTypes = _imageUrlGenerator.SupportedImageFileTypes.ToArray(),
DisallowedUploadedFilesExtensions = _contentSettings.DisallowedUploadedFileExtensions,
AllowedUploadedFileExtensions = _contentSettings.AllowedUploadedFileExtensions,
DisallowedUploadedFilesExtensions = _contentSettings.DisallowedUploadedFileExtensions.ToArray(),
AllowedUploadedFileExtensions = _contentSettings.AllowedUploadedFileExtensions.ToArray(),
MaxFileSize = _runtimeSettings.MaxRequestLength,
};
}

View File

@@ -5,24 +5,26 @@ namespace Umbraco.Extensions;
public static class ContentSettingsExtensions
{
/// <summary>
/// Determines if file extension is allowed for upload based on (optional) white list and black list
/// held in settings.
/// Allow upload if extension is whitelisted OR if there is no whitelist and extension is NOT blacklisted.
/// Determines if file extension is allowed for upload based on (optional) allow list and deny list held in settings.
/// Disallowed file extensions are only considered if there are no allowed file extensions.
/// </summary>
public static bool IsFileAllowedForUpload(this ContentSettings contentSettings, string extension) =>
contentSettings.AllowedUploadedFileExtensions.Any(x => x.InvariantEquals(extension)) ||
(contentSettings.AllowedUploadedFileExtensions.Any() == false &&
contentSettings.DisallowedUploadedFileExtensions.Any(x => x.InvariantEquals(extension)) == false);
/// <param name="contentSettings">The content settings.</param>
/// <param name="extension">The file extension.</param>
/// <returns>
/// <c>true</c> if the file extension is allowed for upload; otherwise, <c>false</c>.
/// </returns>
public static bool IsFileAllowedForUpload(this ContentSettings contentSettings, string extension)
=> contentSettings.AllowedUploadedFileExtensions.Any(x => x.InvariantEquals(extension)) ||
(contentSettings.AllowedUploadedFileExtensions.Any() == false && contentSettings.DisallowedUploadedFileExtensions.Any(x => x.InvariantEquals(extension)) == false);
/// <summary>
/// Gets the auto-fill configuration for a specified property alias.
/// </summary>
/// <param name="contentSettings"></param>
/// <param name="contentSettings">The content settings.</param>
/// <param name="propertyTypeAlias">The property type alias.</param>
/// <returns>The auto-fill configuration for the specified property alias, or null.</returns>
/// <returns>
/// The auto-fill configuration for the specified property alias or <c>null</c> if not configured.
/// </returns>
public static ImagingAutoFillUploadField? GetConfig(this ContentSettings contentSettings, string propertyTypeAlias)
{
ImagingAutoFillUploadField[] autoFillConfigs = contentSettings.Imaging.AutoFillImageProperties;
return autoFillConfigs?.FirstOrDefault(x => x.Alias == propertyTypeAlias);
}
=> contentSettings.Imaging.AutoFillImageProperties.FirstOrDefault(x => x.Alias == propertyTypeAlias);
}

View File

@@ -19,12 +19,11 @@ public class BasicAuthSettings
[DefaultValue(StaticEnabled)]
public bool Enabled { get; set; } = StaticEnabled;
public ISet<string> AllowedIPs { get; set; } = new HashSet<string>();
public string[] AllowedIPs { get; set; } = Array.Empty<string>();
public SharedSecret SharedSecret { get; set; } = new SharedSecret();
public SharedSecret SharedSecret { get; set; } = new();
public bool RedirectToLoginPage { get; set; } = false;
}
public class SharedSecret
@@ -33,5 +32,6 @@ public class SharedSecret
[DefaultValue(StaticHeaderName)]
public string? HeaderName { get; set; } = StaticHeaderName;
public string? Value { get; set; }
}

View File

@@ -31,6 +31,5 @@ public class ContentDashboardSettings
/// <summary>
/// Gets the allowed addresses to retrieve data for the content dashboard.
/// </summary>
/// <value>The URLs.</value>
public string[]? ContentDashboardUrlAllowlist { get; set; }
public ISet<string> ContentDashboardUrlAllowlist { get; set; } = new HashSet<string>();
}

View File

@@ -12,7 +12,7 @@ public class ContentImagingSettings
{
internal const string StaticImageFileTypes = "jpeg,jpg,gif,bmp,png,tiff,tif,webp";
private static readonly ImagingAutoFillUploadField[] DefaultImagingAutoFillUploadField =
private static readonly ISet<ImagingAutoFillUploadField> DefaultImagingAutoFillUploadField = new HashSet<ImagingAutoFillUploadField>
{
new()
{
@@ -28,10 +28,11 @@ public class ContentImagingSettings
/// Gets or sets a value for the collection of accepted image file extensions.
/// </summary>
[DefaultValue(StaticImageFileTypes)]
public string[] ImageFileTypes { get; set; } = StaticImageFileTypes.Split(',');
public ISet<string> ImageFileTypes { get; set; } = new HashSet<string>(StaticImageFileTypes.Split(Constants.CharArrays.Comma));
/// <summary>
/// Gets or sets a value for the imaging autofill following media file upload fields.
/// </summary>
public ImagingAutoFillUploadField[] AutoFillImageProperties { get; set; } = DefaultImagingAutoFillUploadField;
/// <value>
public ISet<ImagingAutoFillUploadField> AutoFillImageProperties { get; set; } = DefaultImagingAutoFillUploadField;
}

View File

@@ -47,7 +47,7 @@ public class ContentSettings
/// <summary>
/// Gets or sets a value for the collection of error pages.
/// </summary>
public ContentErrorPage[] Error404Collection { get; set; } = Array.Empty<ContentErrorPage>();
public ISet<ContentErrorPage> Error404Collection { get; set; } = new HashSet<ContentErrorPage>();
/// <summary>
/// Gets or sets a value for the preview badge mark-up.
@@ -115,18 +115,18 @@ public class ContentSettings
/// <summary>
/// Gets or sets a value for the collection of file extensions that are allowed for upload.
/// </summary>
public string[] AllowedUploadedFileExtensions { get; set; } = Array.Empty<string>();
public ISet<string> AllowedUploadedFileExtensions { get; set; } = new HashSet<string>();
/// <summary>
/// Gets or sets a value for the collection of file extensions that are disallowed for upload.
/// </summary>
[DefaultValue(StaticDisallowedUploadFiles)]
public string[] DisallowedUploadedFileExtensions { get; set; } = StaticDisallowedUploadFiles.Split(',');
public ISet<string> DisallowedUploadedFileExtensions { get; set; } = new HashSet<string>(StaticDisallowedUploadFiles.Split(Constants.CharArrays.Comma));
/// <summary>
/// Gets or sets the allowed external host for media. If empty only relative paths are allowed.
/// </summary>
public string[] AllowedMediaHosts { get; set; } = Array.Empty<string>();
public ISet<string> AllowedMediaHosts { get; set; } = new HashSet<string>();
/// <summary>
/// Gets or sets a value indicating whether to show domain warnings.

View File

@@ -39,8 +39,10 @@ public class DeliveryApiSettings
/// Gets or sets the aliases of the content types that may never be exposed through the Delivery API. Content of these
/// types will never be returned from any Delivery API endpoint, nor added to the query index.
/// </summary>
/// <value>The content type aliases that are not to be exposed.</value>
public string[] DisallowedContentTypeAliases { get; set; } = Array.Empty<string>();
/// <value>
/// The content type aliases that are not to be exposed.
/// </value>
public ISet<string> DisallowedContentTypeAliases { get; set; } = new HashSet<string>();
/// <summary>
/// Gets or sets a value indicating whether the Delivery API should output rich text values as JSON instead of HTML.
@@ -139,15 +141,21 @@ public class DeliveryApiSettings
/// <summary>
/// Gets or sets the URLs allowed to use as redirect targets after a successful login (session authorization).
/// </summary>
/// <value>The URLs allowed as redirect targets.</value>
public Uri[] LoginRedirectUrls { get; set; } = Array.Empty<Uri>();
/// <value>
/// The URLs allowed as redirect targets.
/// </value>
public ISet<Uri> LoginRedirectUrls { get; set; } = new HashSet<Uri>();
/// <summary>
/// Gets or sets the URLs allowed to use as redirect targets after a successful logout (session termination).
/// </summary>
/// <value>The URLs allowed as redirect targets.</value>
/// <remarks>These are only required if logout is to be used.</remarks>
public Uri[] LogoutRedirectUrls { get; set; } = Array.Empty<Uri>();
/// <value>
/// The URLs allowed as redirect targets.
/// </value>
/// <remarks>
/// These are only required if logout is to be used.
/// </remarks>
public ISet<Uri> LogoutRedirectUrls { get; set; } = new HashSet<Uri>();
}
/// <summary>

View File

@@ -33,12 +33,10 @@ public class HealthChecksNotificationSettings
/// <summary>
/// Gets or sets a value for the collection of health check notification methods.
/// </summary>
public IDictionary<string, HealthChecksNotificationMethodSettings> NotificationMethods { get; set; } =
new Dictionary<string, HealthChecksNotificationMethodSettings>();
public IDictionary<string, HealthChecksNotificationMethodSettings> NotificationMethods { get; set; } = new Dictionary<string, HealthChecksNotificationMethodSettings>();
/// <summary>
/// Gets or sets a value for the collection of health checks that are disabled for notifications.
/// </summary>
public List<DisabledHealthCheckSettings> DisabledChecks { get; set; } =
new List<DisabledHealthCheckSettings>();
public IList<DisabledHealthCheckSettings> DisabledChecks { get; set; } = new List<DisabledHealthCheckSettings>();
}

View File

@@ -12,8 +12,7 @@ public class HealthChecksSettings
/// <summary>
/// Gets or sets a value for the collection of healthchecks that are disabled.
/// </summary>
public List<DisabledHealthCheckSettings> DisabledChecks { get; set; } =
new List<DisabledHealthCheckSettings>();
public IList<DisabledHealthCheckSettings> DisabledChecks { get; set; } = new List<DisabledHealthCheckSettings>();
/// <summary>
/// Gets or sets a value for the healthcheck notification settings.

View File

@@ -6,5 +6,5 @@ public class HelpPageSettings
/// <summary>
/// Gets or sets the allowed addresses to retrieve data for the content dashboard.
/// </summary>
public string[]? HelpPageUrlAllowList { get; set; }
public ISet<string> HelpPageUrlAllowList { get; set; } = new HashSet<string>();
}

View File

@@ -70,5 +70,5 @@ public class InstallDefaultDataSettings
/// https://github.com/umbraco/Umbraco-CMS/blob/v9/dev/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs.
/// </para>
/// </remarks>
public IList<string> Values { get; set; } = new List<string>();
public ISet<string> Values { get; set; } = new HashSet<string>();
}

View File

@@ -12,5 +12,5 @@ public class MarketplaceSettings
/// <summary>
/// Gets or sets the additional parameters that are sent to the Marketplace.
/// </summary>
public Dictionary<string, string> AdditionalParameters { get; set; } = new ();
public IDictionary<string, string> AdditionalParameters { get; set; } = new Dictionary<string, string>();
}

View File

@@ -2,7 +2,6 @@
// See LICENSE for more details.
using System.ComponentModel;
using Umbraco.Cms.Core.Configuration.UmbracoSettings;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.Configuration.Models;
@@ -99,5 +98,5 @@ public class RequestHandlerSettings
/// <summary>
/// Add additional character replacements, or override defaults
/// </summary>
public IEnumerable<CharItem>? UserDefinedCharCollection { get; set; }
public ISet<CharItem> UserDefinedCharCollection { get; set; } = new HashSet<CharItem>();
}

View File

@@ -21,10 +21,10 @@ public class TypeFinderSettings
/// By default the entry assemblies for scanning plugin types is the Umbraco DLLs. If you require
/// scanning for plugins based on different root referenced assemblies you can add the assembly name to this list.
/// </summary>
public IEnumerable<string>? AdditionalEntryAssemblies { get; set; }
public ISet<string> AdditionalEntryAssemblies { get; set; } = new HashSet<string>();
/// <summary>
/// Gets or sets a value for the assemblies that will be excluded from scanning.
/// </summary>
public string[] AdditionalAssemblyExclusionEntries { get; set; } = Array.Empty<string>();
public ISet<string> AdditionalAssemblyExclusionEntries { get; set; } = new HashSet<string>();
}

View File

@@ -208,7 +208,7 @@ public static class ServiceCollectionExtensions
var typeFinder = new TypeFinder(
loggerFactory.CreateLogger<TypeFinder>(),
assemblyProvider,
typeFinderSettings.AdditionalAssemblyExclusionEntries,
typeFinderSettings.AdditionalAssemblyExclusionEntries.ToArray(),
typeFinderConfig);
var typeLoader = new TypeLoader(typeFinder, loggerFactory.CreateLogger<TypeLoader>());

View File

@@ -11,17 +11,18 @@ public class RequestHandlerSettingsTests
[Test]
public void Given_CharCollection_With_DefaultEnabled_MergesCollection()
{
var userCollection = new CharItem[]
var settings = new RequestHandlerSettings
{
UserDefinedCharCollection =
{
new() { Char = "test", Replacement = "replace" },
new() { Char = "test2", Replacement = "replace2" },
}
};
var settings = new RequestHandlerSettings { UserDefinedCharCollection = userCollection };
var actual = settings.GetCharReplacements().ToList();
var expectedCollection = RequestHandlerSettings.DefaultCharCollection.ToList();
expectedCollection.AddRange(userCollection);
expectedCollection.AddRange(settings.UserDefinedCharCollection);
Assert.AreEqual(expectedCollection.Count, actual.Count);
Assert.That(actual, Is.EquivalentTo(expectedCollection));
@@ -30,33 +31,32 @@ public class RequestHandlerSettingsTests
[Test]
public void Given_CharCollection_With_DefaultDisabled_ReturnsUserCollection()
{
var userCollection = new CharItem[]
var settings = new RequestHandlerSettings
{
UserDefinedCharCollection =
{
new() { Char = "test", Replacement = "replace" },
new() { Char = "test2", Replacement = "replace2" },
};
var settings = new RequestHandlerSettings
{
UserDefinedCharCollection = userCollection,
},
EnableDefaultCharReplacements = false,
};
var actual = settings.GetCharReplacements().ToList();
Assert.AreEqual(userCollection.Length, actual.Count);
Assert.That(actual, Is.EquivalentTo(userCollection));
Assert.AreEqual(settings.UserDefinedCharCollection.Count, actual.Count);
Assert.That(actual, Is.EquivalentTo(settings.UserDefinedCharCollection));
}
[Test]
public void Given_CharCollection_That_OverridesDefaultValues_ReturnsReplacements()
{
var userCollection = new CharItem[]
var settings = new RequestHandlerSettings
{
UserDefinedCharCollection =
{
new() { Char = "%", Replacement = "percent" },
new() { Char = ".", Replacement = "dot" },
}
};
var settings = new RequestHandlerSettings { UserDefinedCharCollection = userCollection };
var actual = settings.GetCharReplacements().ToList();
Assert.AreEqual(RequestHandlerSettings.DefaultCharCollection.Length, actual.Count);
@@ -70,14 +70,15 @@ public class RequestHandlerSettingsTests
[Test]
public void Given_CharCollection_That_OverridesDefaultValues_And_ContainsNew_ReturnsMergedWithReplacements()
{
var userCollection = new CharItem[]
var settings = new RequestHandlerSettings
{
UserDefinedCharCollection =
{
new() { Char = "%", Replacement = "percent" },
new() { Char = ".", Replacement = "dot" },
new() { Char = "new", Replacement = "new" },
}
};
var settings = new RequestHandlerSettings { UserDefinedCharCollection = userCollection };
var actual = settings.GetCharReplacements().ToList();
// Add 1 to the length, because we're expecting to only add one new one

View File

@@ -41,13 +41,13 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Configuration.Models.Validati
private static ContentSettings BuildContentSettings(string culture = "en-US", string autoFillImagePropertyAlias = "testAlias") =>
new ContentSettings
{
Error404Collection = new ContentErrorPage[]
Error404Collection =
{
new() { Culture = culture, ContentId = 1 },
},
Imaging = new ContentImagingSettings
Imaging =
{
AutoFillImageProperties = new ImagingAutoFillUploadField[]
AutoFillImageProperties =
{
new() { Alias = autoFillImagePropertyAlias, WidthFieldAlias = "w", HeightFieldAlias = "h", LengthFieldAlias = "l", ExtensionFieldAlias = "e" },
},

View File

@@ -1,4 +1,4 @@
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
@@ -206,7 +206,10 @@ public class PublishedContentCacheTests : DeliveryApiTests
private IOptionsMonitor<DeliveryApiSettings> CreateDeliveryApiSettings(string[]? disallowedContentTypeAliases = null)
{
var deliveryApiSettings = new DeliveryApiSettings { DisallowedContentTypeAliases = disallowedContentTypeAliases ?? Array.Empty<string>() };
var deliveryApiSettings = new DeliveryApiSettings
{
DisallowedContentTypeAliases = new HashSet<string>(disallowedContentTypeAliases ?? Array.Empty<string>())
};
var deliveryApiOptionsMonitorMock = new Mock<IOptionsMonitor<DeliveryApiSettings>>();
deliveryApiOptionsMonitorMock.SetupGet(s => s.CurrentValue).Returns(deliveryApiSettings);
return deliveryApiOptionsMonitorMock.Object;

View File

@@ -32,10 +32,12 @@ public class BasicAuthServiceTests
[TestCase("125.125.124.1", "125.125.125.0/24", ExpectedResult = false)]
public bool IsIpAllowListed(string clientIpAddress, string commaSeperatedAllowlist)
{
var allowedIPs = commaSeperatedAllowlist.Split(",").Select(x => x.Trim()).ToArray();
var sut = new BasicAuthService(
Mock.Of<IOptionsMonitor<BasicAuthSettings>>(_ =>
_.CurrentValue == new BasicAuthSettings { AllowedIPs = allowedIPs }),
Mock.Of<IOptionsMonitor<BasicAuthSettings>>(x =>
x.CurrentValue == new BasicAuthSettings
{
AllowedIPs = new HashSet<string>(commaSeperatedAllowlist.Split(',', StringSplitOptions.TrimEntries))
}),
new IpAddressUtilities());
return sut.IsIpAllowListed(IPAddress.Parse(clientIpAddress));

View File

@@ -17,7 +17,6 @@ public class DefaultShortStringHelperTestsWithoutSetup
{
var requestHandlerSettings = new RequestHandlerSettings
{
UserDefinedCharCollection = Array.Empty<CharItem>(),
EnableDefaultCharReplacements = false,
ConvertUrlsToAscii = "false",
};
@@ -46,7 +45,6 @@ public class DefaultShortStringHelperTestsWithoutSetup
{
var requestHandlerSettings = new RequestHandlerSettings
{
UserDefinedCharCollection = Array.Empty<CharItem>(),
EnableDefaultCharReplacements = false,
ConvertUrlsToAscii = "false",
};
@@ -382,7 +380,6 @@ public class DefaultShortStringHelperTestsWithoutSetup
{
var requestHandlerSettings = new RequestHandlerSettings
{
UserDefinedCharCollection = Array.Empty<CharItem>(),
EnableDefaultCharReplacements = false,
ConvertUrlsToAscii = "false",
};