diff --git a/README.md b/README.md index 0b2f5e54..eea0cd0a 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,17 @@ A breaking change is introduced which is related to System.Linq.Dynamic.Core Dyn - The `LinqMatcher` is not allowed. - The [Handlebars.Net.Helpers.DynamicLinq](https://www.nuget.org/packages/Handlebars.Net.Helpers.DynamicLinq) package is not included anymore. +### 1.8.0 +Some breaking changes are introduced in this version: + +#### Handlebars.Net `File`-helper +By default, the internal Handlebars.Net `File`-helper is not allowed anymore because of potential security issues. +To still enable this feature, you need to set the `AllowedCustomHandlebarHelpers` property to `File` in the `HandlebarsSettings` property in `WireMockServerSettings`. + +#### Handlebars.Net `Environment`-helper +By default, the Handlebars.Net `Environment`-helper is not automatically allowed anymore because of potential security issues. +To still enable this feature, you need to add the `Environment` category to the `AllowedHandlebarsHelpers` list-property in the `HandlebarsSettings` property in `WireMockServerSettings`. + --- ## :memo: Development diff --git a/src/WireMock.Net.Abstractions/Types/CustomHandlebarHelpers.cs b/src/WireMock.Net.Abstractions/Types/CustomHandlebarsHelpers.cs similarity index 82% rename from src/WireMock.Net.Abstractions/Types/CustomHandlebarHelpers.cs rename to src/WireMock.Net.Abstractions/Types/CustomHandlebarsHelpers.cs index 4f45753c..89046319 100644 --- a/src/WireMock.Net.Abstractions/Types/CustomHandlebarHelpers.cs +++ b/src/WireMock.Net.Abstractions/Types/CustomHandlebarsHelpers.cs @@ -6,7 +6,7 @@ namespace WireMock.Types; /// A enum defining the supported Handlebar helpers. /// [Flags] -public enum CustomHandlebarHelpers +public enum CustomHandlebarsHelpers { None = 0, diff --git a/src/WireMock.Net/Settings/HandlebarsSettings.cs b/src/WireMock.Net/Settings/HandlebarsSettings.cs new file mode 100644 index 00000000..61a47e42 --- /dev/null +++ b/src/WireMock.Net/Settings/HandlebarsSettings.cs @@ -0,0 +1,50 @@ +// Copyright © WireMock.Net + +using HandlebarsDotNet.Helpers.Enums; +using JetBrains.Annotations; +using WireMock.Types; + +namespace WireMock.Settings; + +/// +/// HandlebarsSettings +/// +[PublicAPI] +public class HandlebarsSettings +{ + internal static readonly Category[] DefaultAllowedHandlebarsHelpers = + [ + Category.Boolean, + Category.Constants, + Category.DateTime, + Category.Enumerable, + Category.Humanizer, + Category.JsonPath, + Category.Math, + Category.Object, + Category.Random, + Category.Regex, + Category.String, + Category.Url, + Category.Xeger, + Category.XPath, + Category.Xslt + ]; + + /// + /// Defines the allowed custom HandlebarsHelpers which can be used. Possible values are: + /// - (Default) + /// - + /// - + /// + [PublicAPI] + public CustomHandlebarsHelpers AllowedCustomHandlebarsHelpers { get; set; } = CustomHandlebarsHelpers.None; + + /// + /// Defines the allowed HandlebarHelpers which can be used. + /// + /// By default, all categories except and are registered. + /// + [PublicAPI] + public Category[] AllowedHandlebarsHelpers { get; set; } = DefaultAllowedHandlebarsHelpers; +} \ No newline at end of file diff --git a/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs b/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs index 92ca7ccc..01694f01 100644 --- a/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs +++ b/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs @@ -98,7 +98,7 @@ public class ProxyAndRecordSettings : HttpClientSettings public bool UseDefinedRequestMatchers { get; set; } /// - /// Append an unique GUID to the filename from the saved mapping file. + /// Append a unique GUID to the filename from the saved mapping file. /// public bool AppendGuidToSavedMappingFile { get; set; } diff --git a/src/WireMock.Net/Settings/ProxyUrlReplaceSettings.cs b/src/WireMock.Net/Settings/ProxyUrlReplaceSettings.cs index 863c9615..25a6efb1 100644 --- a/src/WireMock.Net/Settings/ProxyUrlReplaceSettings.cs +++ b/src/WireMock.Net/Settings/ProxyUrlReplaceSettings.cs @@ -18,7 +18,7 @@ public class ProxyUrlReplaceSettings public string NewValue { get; set; } = null!; /// - /// Defines if the case should be ignore when replacing. + /// Defines if the case should be ignored when replacing. /// public bool IgnoreCase { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net/Settings/SimpleSettingsParser.cs b/src/WireMock.Net/Settings/SimpleSettingsParser.cs index ce5b94e2..54fa92bb 100644 --- a/src/WireMock.Net/Settings/SimpleSettingsParser.cs +++ b/src/WireMock.Net/Settings/SimpleSettingsParser.cs @@ -70,6 +70,11 @@ internal class SimpleSettingsParser return Arguments.ContainsKey(name); } + public bool ContainsAny(params string[] names) + { + return names.Any(Arguments.ContainsKey); + } + public string[] GetValues(string name, string[] defaultValue) { return Contains(name) ? Arguments[name] : defaultValue; @@ -142,6 +147,28 @@ internal class SimpleSettingsParser }, defaultValue); } + public TEnum[] GetEnumValues(string name, TEnum[] defaultValues) + where TEnum : struct + { + var values = GetValues(name); + if (values == null) + { + return defaultValues; + } + + var enums = new List(); + + foreach (var value in values) + { + if (Enum.TryParse(value, true, out var enumValue)) + { + enums.Add(enumValue); + } + } + + return enums.ToArray(); + } + public string GetStringValue(string name, string defaultValue) { return GetValue(name, values => values.FirstOrDefault() ?? defaultValue, defaultValue); diff --git a/src/WireMock.Net/Settings/WebProxySettings.cs b/src/WireMock.Net/Settings/WebProxySettings.cs index 2002164b..ba8ef940 100644 --- a/src/WireMock.Net/Settings/WebProxySettings.cs +++ b/src/WireMock.Net/Settings/WebProxySettings.cs @@ -16,13 +16,13 @@ public class WebProxySettings public string Address { get; set; } = null!; /// - /// The user name associated with the credentials. + /// The username associated with the credentials. /// [PublicAPI] public string? UserName { get; set; } /// - /// The password for the user name associated with the credentials. + /// The password for the username associated with the credentials. /// [PublicAPI] public string? Password { get; set; } diff --git a/src/WireMock.Net/Settings/WireMockServerSettings.cs b/src/WireMock.Net/Settings/WireMockServerSettings.cs index 2eb23a41..1066ac6b 100644 --- a/src/WireMock.Net/Settings/WireMockServerSettings.cs +++ b/src/WireMock.Net/Settings/WireMockServerSettings.cs @@ -331,11 +331,8 @@ public class WireMockServerSettings public string? AdminPath { get; set; } /// - /// Defines the allowed custom HandlebarHelpers which can be used. Possible values are: - /// - (Default) - /// - - /// - + /// Defines the additional Handlebars Settings. /// [PublicAPI] - public CustomHandlebarHelpers AllowedCustomHandlebarHelpers { get; set; } = CustomHandlebarHelpers.None; + public HandlebarsSettings? HandlebarsSettings { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs b/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs index 23acf5d6..c7d2a4f7 100644 --- a/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs +++ b/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs @@ -50,7 +50,6 @@ public static class WireMockServerSettingsParser AdminPath = parser.GetStringValue(nameof(WireMockServerSettings.AdminPath), "/__admin"), AllowBodyForAllHttpMethods = parser.GetBoolValue(nameof(WireMockServerSettings.AllowBodyForAllHttpMethods)), AllowCSharpCodeMatcher = parser.GetBoolValue(nameof(WireMockServerSettings.AllowCSharpCodeMatcher)), - AllowedCustomHandlebarHelpers = parser.GetEnumValue(nameof(WireMockServerSettings.AllowedCustomHandlebarHelpers), CustomHandlebarHelpers.None), AllowOnlyDefinedHttpStatusCodeInResponse = parser.GetBoolValue(nameof(WireMockServerSettings.AllowOnlyDefinedHttpStatusCodeInResponse)), AllowPartialMapping = parser.GetBoolValue(nameof(WireMockServerSettings.AllowPartialMapping)), Culture = parser.GetValue(nameof(WireMockServerSettings.Culture), strings => CultureInfoUtils.Parse(strings.FirstOrDefault()), CultureInfo.CurrentCulture), @@ -85,6 +84,7 @@ public static class WireMockServerSettingsParser ParsePortSettings(settings, parser); ParseProxyAndRecordSettings(settings, parser); ParseCertificateSettings(settings, parser); + ParseHandlebarsSettings(settings, parser); return true; } @@ -153,7 +153,7 @@ public static class WireMockServerSettingsParser } else if (settings.HostingScheme is null) { - settings.Urls = parser.GetValues("Urls", new[] { "http://*:9091/" }); + settings.Urls = parser.GetValues("Urls", ["http://*:9091/"]); } } @@ -167,12 +167,25 @@ public static class WireMockServerSettingsParser X509CertificateFilePath = parser.GetStringValue("X509CertificateFilePath"), X509CertificatePassword = parser.GetStringValue("X509CertificatePassword") }; + if (certificateSettings.IsDefined) { settings.CertificateSettings = certificateSettings; } } + private static void ParseHandlebarsSettings(WireMockServerSettings settings, SimpleSettingsParser parser) + { + if (parser.ContainsAny(nameof(HandlebarsSettings.AllowedCustomHandlebarsHelpers), nameof(HandlebarsSettings.AllowedHandlebarsHelpers))) + { + settings.HandlebarsSettings = new HandlebarsSettings + { + AllowedCustomHandlebarsHelpers = parser.GetEnumValue(nameof(HandlebarsSettings.AllowedCustomHandlebarsHelpers), CustomHandlebarsHelpers.None), + AllowedHandlebarsHelpers = parser.GetEnumValues(nameof(HandlebarsSettings.AllowedHandlebarsHelpers), HandlebarsSettings.DefaultAllowedHandlebarsHelpers) + }; + } + } + private static void ParseWebProxyAddressSettings(ProxyAndRecordSettings settings, SimpleSettingsParser parser) { string? proxyAddress = parser.GetStringValue("WebProxyAddress"); diff --git a/src/WireMock.Net/Transformers/Handlebars/FileHelpers.cs b/src/WireMock.Net/Transformers/Handlebars/FileHelpers.cs index df135e59..92a41383 100644 --- a/src/WireMock.Net/Transformers/Handlebars/FileHelpers.cs +++ b/src/WireMock.Net/Transformers/Handlebars/FileHelpers.cs @@ -4,8 +4,10 @@ using HandlebarsDotNet; using HandlebarsDotNet.Helpers.Attributes; using HandlebarsDotNet.Helpers.Enums; using HandlebarsDotNet.Helpers.Helpers; +using HandlebarsDotNet.Helpers.Options; using Stef.Validation; using WireMock.Handlers; +using WireMock.Settings; namespace WireMock.Transformers.Handlebars; @@ -15,9 +17,9 @@ internal class FileHelpers : BaseHelpers, IHelpers private readonly IFileSystemHandler _fileSystemHandler; - public FileHelpers(IHandlebars context, IFileSystemHandler fileSystemHandler) : base(context) + public FileHelpers(IHandlebars context, WireMockServerSettings settings) : base(context, new HandlebarsHelpersOptions()) { - _fileSystemHandler = Guard.NotNull(fileSystemHandler); + _fileSystemHandler = Guard.NotNull(settings.FileSystemHandler); } [HandlebarsWriter(WriterType.String, usage: HelperUsage.Both, passContext: true, name: Name)] diff --git a/src/WireMock.Net/Transformers/Handlebars/WireMockHandlebarsHelpers.cs b/src/WireMock.Net/Transformers/Handlebars/WireMockHandlebarsHelpers.cs index 96331c77..70fd7633 100644 --- a/src/WireMock.Net/Transformers/Handlebars/WireMockHandlebarsHelpers.cs +++ b/src/WireMock.Net/Transformers/Handlebars/WireMockHandlebarsHelpers.cs @@ -40,9 +40,9 @@ internal static class WireMockHandlebarsHelpers o.CustomHelperPaths = paths; o.CustomHelpers = new Dictionary(); - if (settings.AllowedCustomHandlebarHelpers.HasFlag(CustomHandlebarHelpers.File)) + if (settings.HandlebarsSettings?.AllowedCustomHandlebarsHelpers.HasFlag(CustomHandlebarsHelpers.File) == true) { - o.CustomHelpers.Add(FileHelpers.Name, new FileHelpers(handlebarsContext, settings.FileSystemHandler)); + o.CustomHelpers.Add(FileHelpers.Name, new FileHelpers(handlebarsContext, settings)); } }); } diff --git a/src/WireMock.Net/WireMock.Net.csproj b/src/WireMock.Net/WireMock.Net.csproj index 6eb56347..ce422f0b 100644 --- a/src/WireMock.Net/WireMock.Net.csproj +++ b/src/WireMock.Net/WireMock.Net.csproj @@ -182,13 +182,13 @@ - - - - - - - + + + + + + + diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsFileTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsFileTests.cs index 952a6ecc..3528038a 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsFileTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsFileTests.cs @@ -4,7 +4,6 @@ using System; using System.Threading.Tasks; using FluentAssertions; using HandlebarsDotNet; -using HandlebarsDotNet.Helpers; using Moq; using Newtonsoft.Json.Linq; using NFluent; @@ -12,7 +11,6 @@ using WireMock.Handlers; using WireMock.Models; using WireMock.ResponseBuilders; using WireMock.Settings; -using WireMock.Transformers.Handlebars; using WireMock.Types; using Xunit; @@ -35,7 +33,10 @@ public class ResponseWithHandlebarsFileTests _settings = new() { - AllowedCustomHandlebarHelpers = CustomHandlebarHelpers.File, + HandlebarsSettings = new HandlebarsSettings + { + AllowedCustomHandlebarsHelpers = CustomHandlebarsHelpers.File + }, FileSystemHandler = _filesystemHandlerMock.Object }; } @@ -117,7 +118,6 @@ public class ResponseWithHandlebarsFileTests // Assign var settings = new WireMockServerSettings { - AllowedCustomHandlebarHelpers = CustomHandlebarHelpers.None, FileSystemHandler = _filesystemHandlerMock.Object }; var request = new RequestMessage(new UrlDetails("http://localhost:1234?id=x"), "GET", ClientIp);