Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions Fluid.Tests/MiscFiltersTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,50 @@ public async Task Sha256()
Assert.Equal("c7ac4687585ab5d3d5030db5a5cfc959fdf4e608cc396f1f615db345e35adb9e", result.ToStringValue());
}

[Theory]
[InlineData(null, "Fluid", "")]
[InlineData("secret_key", null, "")]
[InlineData("", "", "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d")]
[InlineData("", "Fluid", "47ab4d87fabf7a7162d59c57298780904de9e245")]
[InlineData("secret_key", "Fluid", "1061ea276551355150b8581aa64dca829d41e357")]
public async Task HmacSha1(string key, string value, string expected)
{
// Arrange
FluidValue input = value is null
? NilValue.Empty
: new StringValue(value);
var arguments = new FilterArguments(FluidValue.Create(key, TemplateOptions.Default));
var context = new TemplateContext();

// Act
var result = await MiscFilters.HmacSha1(input, arguments, context);

// Assert
Assert.Equal(expected, result.ToStringValue());
}

[Theory]
[InlineData(null, "Fluid", "")]
[InlineData("secret_key", null, "")]
[InlineData("", "", "b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad")]
[InlineData("", "Fluid", "e9f2db8bd3900c469e4b560227c5d53b48f644208a13de05bb400f7611d1a623")]
[InlineData("secret_key", "Fluid", "ac08ee5cdd007e1069680e93eb512049f5ff12afd0fe101de5c9b5043a047ea4")]
public async Task HmacSha256(string key, string value, string expected)
{
// Arrange
FluidValue input = value is null
? NilValue.Empty
: new StringValue(value);
var arguments = new FilterArguments(FluidValue.Create(key, TemplateOptions.Default));
var context = new TemplateContext();

// Act
var result = await MiscFilters.HmacSha256(input, arguments, context);

// Assert
Assert.Equal(expected, result.ToStringValue());
}

public static class TestObjects
{
public class Node
Expand Down
45 changes: 45 additions & 0 deletions Fluid/Filters/MiscFilters.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using Fluid.Utils;
using Fluid.Values;
using System.Buffers;
using System.Globalization;
using System.Net;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using TimeZoneConverter;
Expand Down Expand Up @@ -41,6 +43,8 @@ public static FilterCollection WithMiscFilters(this FilterCollection filters)
filters.AddFilter("md5", MD5);
filters.AddFilter("sha1", Sha1);
filters.AddFilter("sha256", Sha256);
filters.AddFilter("hmac_sha1", HmacSha1);
filters.AddFilter("hmac_sha256", HmacSha256);

return filters;
}
Expand Down Expand Up @@ -933,5 +937,46 @@ public static ValueTask<FluidValue> Sha256(FluidValue input, FilterArguments arg
return new StringValue(builder.ToString());
#endif
}

public static ValueTask<FluidValue> HmacSha1(FluidValue input, FilterArguments arguments, TemplateContext context) => ComputeHmac("HMACSHA1", input, arguments);

public static ValueTask<FluidValue> HmacSha256(FluidValue input, FilterArguments arguments, TemplateContext context) => ComputeHmac("HMACSHA256", input, arguments);

private static ValueTask<FluidValue> ComputeHmac(string algorithm, FluidValue input, FilterArguments arguments)
{
var key = arguments.At(0);
if (key.IsNil() || input.IsNil())
{
return StringValue.Empty;
}

var value = input.ToStringValue();
var keyBytes = Encoding.UTF8.GetBytes(key.ToStringValue());

#if NET6_0_OR_GREATER
#pragma warning disable CA5350
var hash = algorithm switch
{
"HMACSHA1" => HMACSHA1.HashData(keyBytes, Encoding.UTF8.GetBytes(value)),
"HMACSHA256" => HMACSHA256.HashData(keyBytes, Encoding.UTF8.GetBytes(value)),
_ => throw new ArgumentException("Unsupported HMAC algorithm", nameof(algorithm))
};
#pragma warning restore CA5350

return new StringValue(HexUtilities.ToHexLower(hash));
#else
using var provider = HMAC.Create(algorithm);
provider.Key = keyBytes;
var builder = new StringBuilder(64);
#pragma warning disable CA1850
foreach (var b in provider.ComputeHash(Encoding.UTF8.GetBytes(value)))
#pragma warning restore CA1850
{
builder.Append(b.ToString("x2"));
}

return new StringValue(builder.ToString());
#endif
}
}
}