Skip to content

Commit ff36c1e

Browse files
authored
Merge commit from fork
1 parent be55022 commit ff36c1e

File tree

8 files changed

+86
-20
lines changed

8 files changed

+86
-20
lines changed

‎README.md

+5
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ A breaking change is introduced which is related to System.Linq.Dynamic.Core Dyn
6464
- The `LinqMatcher` is not allowed.
6565
- The [Handlebars.Net.Helpers.DynamicLinq](https://www.nuget.org/packages/Handlebars.Net.Helpers.DynamicLinq) package is not included anymore.
6666

67+
### 1.8.0
68+
A breaking change is introduced which is related to the usage of the custom Handlebars.Net `File`-helper.
69+
By default this is not allowed anymore because of security reasons (insecure server-side template injection).
70+
To still enable this feature, you need to set the `AllowedCustomHandlebarHelpers` property to `File` in the `WireMockServerSettings` class.
71+
6772
---
6873

6974
## :memo: Development
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
3+
namespace WireMock.Types;
4+
5+
/// <summary>
6+
/// A enum defining the supported Handlebar helpers.
7+
/// </summary>
8+
[Flags]
9+
public enum CustomHandlebarHelpers
10+
{
11+
None = 0,
12+
13+
File = 1,
14+
15+
All = File
16+
}

‎src/WireMock.Net/Settings/WireMockServerSettings.cs

+9
Original file line numberDiff line numberDiff line change
@@ -329,4 +329,13 @@ public class WireMockServerSettings
329329
/// </summary>
330330
[PublicAPI]
331331
public string? AdminPath { get; set; }
332+
333+
/// <summary>
334+
/// Defines the allowed custom HandlebarHelpers which can be used. Possible values are:
335+
/// - <see cref="CustomHandlebarHelpers.None"/> (Default)
336+
/// - <see cref="CustomHandlebarHelpers.File"/>
337+
/// - <see cref="CustomHandlebarHelpers.All"/>
338+
/// </summary>
339+
[PublicAPI]
340+
public CustomHandlebarHelpers AllowedCustomHandlebarHelpers { get; set; } = CustomHandlebarHelpers.None;
332341
}

‎src/WireMock.Net/Settings/WireMockServerSettingsParser.cs

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public static bool TryParseArguments(string[] args, IDictionary? environment, [N
5050
AdminPath = parser.GetStringValue(nameof(WireMockServerSettings.AdminPath), "/__admin"),
5151
AllowBodyForAllHttpMethods = parser.GetBoolValue(nameof(WireMockServerSettings.AllowBodyForAllHttpMethods)),
5252
AllowCSharpCodeMatcher = parser.GetBoolValue(nameof(WireMockServerSettings.AllowCSharpCodeMatcher)),
53+
AllowedCustomHandlebarHelpers = parser.GetEnumValue(nameof(WireMockServerSettings.AllowedCustomHandlebarHelpers), CustomHandlebarHelpers.None),
5354
AllowOnlyDefinedHttpStatusCodeInResponse = parser.GetBoolValue(nameof(WireMockServerSettings.AllowOnlyDefinedHttpStatusCodeInResponse)),
5455
AllowPartialMapping = parser.GetBoolValue(nameof(WireMockServerSettings.AllowPartialMapping)),
5556
Culture = parser.GetValue(nameof(WireMockServerSettings.Culture), strings => CultureInfoUtils.Parse(strings.FirstOrDefault()), CultureInfo.CurrentCulture),

‎src/WireMock.Net/Transformers/Handlebars/FileHelpers.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,21 @@ namespace WireMock.Transformers.Handlebars;
1111

1212
internal class FileHelpers : BaseHelpers, IHelpers
1313
{
14+
internal const string Name = "File";
15+
1416
private readonly IFileSystemHandler _fileSystemHandler;
1517

1618
public FileHelpers(IHandlebars context, IFileSystemHandler fileSystemHandler) : base(context)
1719
{
1820
_fileSystemHandler = Guard.NotNull(fileSystemHandler);
1921
}
2022

21-
[HandlebarsWriter(WriterType.String, usage: HelperUsage.Both, passContext: true, name: "File")]
23+
[HandlebarsWriter(WriterType.String, usage: HelperUsage.Both, passContext: true, name: Name)]
2224
public string Read(Context context, string path)
2325
{
2426
var templateFunc = Context.Compile(path);
25-
var transformed = templateFunc(context.Value);
26-
return _fileSystemHandler.ReadResponseBodyAsString(transformed);
27+
var transformedPath = templateFunc(context.Value);
28+
return _fileSystemHandler.ReadResponseBodyAsString(transformedPath);
2729
}
2830

2931
public Category Category => Category.Custom;

‎src/WireMock.Net/Transformers/Handlebars/HandlebarsContextFactory.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public ITransformerContext Create()
2323
};
2424
var handlebars = HandlebarsDotNet.Handlebars.Create(config);
2525

26-
WireMockHandlebarsHelpers.Register(handlebars, _settings.FileSystemHandler);
26+
WireMockHandlebarsHelpers.Register(handlebars, _settings);
2727

2828
_settings.HandlebarsRegistrationCallback?.Invoke(handlebars, _settings.FileSystemHandler);
2929

‎src/WireMock.Net/Transformers/Handlebars/WireMockHandlebarsHelpers.cs

+12-12
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,20 @@
22

33
using System;
44
using System.Collections.Generic;
5-
using System.Diagnostics;
65
using System.IO;
7-
using System.Reflection;
86
using HandlebarsDotNet;
97
using HandlebarsDotNet.Helpers;
108
using HandlebarsDotNet.Helpers.Helpers;
11-
using WireMock.Handlers;
9+
using WireMock.Settings;
10+
using WireMock.Types;
1211

1312
namespace WireMock.Transformers.Handlebars;
1413

1514
internal static class WireMockHandlebarsHelpers
1615
{
17-
public static void Register(IHandlebars handlebarsContext, IFileSystemHandler fileSystemHandler)
16+
internal static void Register(IHandlebars handlebarsContext, WireMockServerSettings settings)
1817
{
19-
// Register https://.com/StefH/Handlebars.Net.Helpers
18+
// Register https://.com/Handlebars.Net/Handlebars.Net.Helpers
2019
HandlebarsHelpers.Register(handlebarsContext, o =>
2120
{
2221
var paths = new List<string>
@@ -33,17 +32,18 @@ void Add(string? path, ICollection<string> customHelperPaths)
3332
customHelperPaths.Add(path!);
3433
}
3534
}
36-
Add(Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location), paths);
37-
Add(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location), paths);
38-
Add(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), paths);
39-
Add(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule?.FileName), paths);
35+
Add(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly()?.Location), paths);
36+
Add(Path.GetDirectoryName(System.Reflection.Assembly.GetCallingAssembly().Location), paths);
37+
Add(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), paths);
38+
Add(Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName), paths);
4039
#endif
4140
o.CustomHelperPaths = paths;
4241

43-
o.CustomHelpers = new Dictionary<string, IHelpers>
42+
o.CustomHelpers = new Dictionary<string, IHelpers>();
43+
if (settings.AllowedCustomHandlebarHelpers.HasFlag(CustomHandlebarHelpers.File))
4444
{
45-
{ "File", new FileHelpers(handlebarsContext, fileSystemHandler) }
46-
};
45+
o.CustomHelpers.Add(FileHelpers.Name, new FileHelpers(handlebarsContext, settings.FileSystemHandler));
46+
}
4747
});
4848
}
4949

‎test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsFileTests.cs

+37-4
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
// Copyright © WireMock.Net
22

3+
using System;
34
using System.Threading.Tasks;
5+
using FluentAssertions;
46
using HandlebarsDotNet;
7+
using HandlebarsDotNet.Helpers;
58
using Moq;
69
using Newtonsoft.Json.Linq;
710
using NFluent;
811
using WireMock.Handlers;
912
using WireMock.Models;
1013
using WireMock.ResponseBuilders;
1114
using WireMock.Settings;
15+
using WireMock.Transformers.Handlebars;
16+
using WireMock.Types;
1217
using Xunit;
1318

1419
namespace WireMock.Net.Tests.ResponseBuilders;
1520

1621
public class ResponseWithHandlebarsFileTests
1722
{
18-
private readonly WireMockServerSettings _settings = new();
1923
private const string ClientIp = "::1";
2024

25+
private readonly WireMockServerSettings _settings;
2126
private readonly Mock<IMapping> _mappingMock;
2227
private readonly Mock<IFileSystemHandler> _filesystemHandlerMock;
2328

@@ -28,7 +33,11 @@ public ResponseWithHandlebarsFileTests()
2833
_filesystemHandlerMock = new Mock<IFileSystemHandler>(MockBehavior.Strict);
2934
_filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny<string>())).Returns("abc");
3035

31-
_settings.FileSystemHandler = _filesystemHandlerMock.Object;
36+
_settings = new()
37+
{
38+
AllowedCustomHandlebarHelpers = CustomHandlebarHelpers.File,
39+
FileSystemHandler = _filesystemHandlerMock.Object
40+
};
3241
}
3342

3443
[Fact]
@@ -48,7 +57,7 @@ public async Task Response_ProvideResponseAsync_Handlebars_File()
4857
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
4958

5059
// Assert
51-
JObject j = JObject.FromObject(response.Message.BodyData.BodyAsJson);
60+
var j = JObject.FromObject(response.Message.BodyData.BodyAsJson);
5261
Check.That(j["Data"].Value<string>()).Equals("abc");
5362

5463
// Verify
@@ -73,7 +82,7 @@ public async Task Response_ProvideResponseAsync_Handlebars_File_Replace()
7382
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
7483

7584
// Assert
76-
JObject j = JObject.FromObject(response.Message.BodyData.BodyAsJson);
85+
var j = JObject.FromObject(response.Message.BodyData.BodyAsJson);
7786
Check.That(j["Data"].Value<string>()).Equals("abc");
7887

7988
// Verify
@@ -101,4 +110,28 @@ public void Response_ProvideResponseAsync_Handlebars_File_WithMissingArgument_Th
101110
_filesystemHandlerMock.Verify(fs => fs.ReadResponseBodyAsString(It.IsAny<string>()), Times.Never);
102111
_filesystemHandlerMock.VerifyNoOtherCalls();
103112
}
113+
114+
[Fact]
115+
public void Response_ProvideResponseAsync_Handlebars_File_NotAllowed_Throws_HandlebarsRuntimeException()
116+
{
117+
// Assign
118+
var settings = new WireMockServerSettings
119+
{
120+
AllowedCustomHandlebarHelpers = CustomHandlebarHelpers.None,
121+
FileSystemHandler = _filesystemHandlerMock.Object
122+
};
123+
var request = new RequestMessage(new UrlDetails("http://localhost:1234?id=x"), "GET", ClientIp);
124+
125+
var responseBuilder = Response.Create()
126+
.Witdy("{{File \"{{request.query.id}}.json\"}}")
127+
.WithTransformer();
128+
129+
// Act
130+
Func<Task> action = () => responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, settings);
131+
132+
action.Should().ThrowAsync<HandlebarsRuntimeException>();
133+
134+
// Verify
135+
_filesystemHandlerMock.VerifyNoOtherCalls();
136+
}
104137
}

0 commit comments

Comments
 (0)