diff --git a/Fluid.Tests/IncludeStatementTests.cs b/Fluid.Tests/IncludeStatementTests.cs index 213c51e5..797b3c79 100644 --- a/Fluid.Tests/IncludeStatementTests.cs +++ b/Fluid.Tests/IncludeStatementTests.cs @@ -20,7 +20,7 @@ public class IncludeStatementTests #endif [Fact] - public async Task IncludeSatement_ShouldThrowFileNotFoundException_IfTheFileProviderIsNotPresent() + public async Task IncludeStatement_ShouldThrowFileNotFoundException_IfTheFileProviderIsNotPresent() { var expression = new LiteralExpression(new StringValue("_Partial.liquid")); var sw = new StringWriter(); @@ -39,7 +39,7 @@ public async Task IncludeSatement_ShouldThrowFileNotFoundException_IfTheFileProv } [Fact] - public async Task IncludeSatement_ShouldLoadPartial_IfThePartialsFolderExist() + public async Task IncludeStatement_ShouldLoadPartial_IfThePartialsFolderExist() { var expression = new LiteralExpression(new StringValue("_Partial.liquid")); @@ -64,7 +64,7 @@ public async Task IncludeSatement_ShouldLoadPartial_IfThePartialsFolderExist() } [Fact] - public async Task IncludeSatement_ShouldLoadCorrectTemplate_IfTheMemberExpressionValueChanges() + public async Task IncludeStatement_ShouldLoadCorrectTemplate_IfTheMemberExpressionValueChanges() { var expression = new MemberExpression(new IdentifierSegment("Firstname")); var sw = new StringWriter(); @@ -109,7 +109,7 @@ public async Task IncludeSatement_ShouldLoadCorrectTemplate_IfTheMemberExpressio } [Fact] - public async Task IncludeSatement_WithInlinevariableAssignment_ShouldBeEvaluated() + public async Task IncludeStatement_WithInlinevariableAssignment_ShouldBeEvaluated() { var expression = new LiteralExpression(new StringValue("_Partial.liquid")); var assignStatements = new List @@ -138,7 +138,7 @@ public async Task IncludeSatement_WithInlinevariableAssignment_ShouldBeEvaluated } [Fact] - public async Task IncludeSatement_WithTagParams_ShouldBeEvaluated() + public async Task IncludeStatement_WithTagParams_ShouldBeEvaluated() { var pathExpression = new LiteralExpression(new StringValue("color")); var withExpression = new LiteralExpression(new StringValue("blue")); @@ -163,7 +163,7 @@ public async Task IncludeSatement_WithTagParams_ShouldBeEvaluated() } [Fact] - public async Task IncludeSatement_ShouldLimitRecursion() + public async Task IncludeStatement_ShouldLimitRecursion() { var expression = new LiteralExpression(new StringValue("_Partial.liquid")); var sw = new StringWriter(); diff --git a/Fluid.Tests/MiscFiltersTests.cs b/Fluid.Tests/MiscFiltersTests.cs index 6185f9d4..616ef56a 100644 --- a/Fluid.Tests/MiscFiltersTests.cs +++ b/Fluid.Tests/MiscFiltersTests.cs @@ -101,6 +101,8 @@ public async Task DecodeUrl() [Theory] [InlineData("a<>:a?", "YTw+OmE/")] + [InlineData("Hell", "SGVsbA==")] + [InlineData("Hello", "SGVsbG8=")] public async Task Base64Encode(string value, string expected) { var input = new StringValue(value); @@ -115,6 +117,8 @@ public async Task Base64Encode(string value, string expected) [Theory] [InlineData("YTw+OmE/", "a<>:a?")] + [InlineData("SGVsbA==", "Hell")] + [InlineData("SGVsbG8=", "Hello")] public async Task Base64Decode(string value, string expected) { var input = new StringValue(value); @@ -129,6 +133,8 @@ public async Task Base64Decode(string value, string expected) [Theory] [InlineData("a<>:a?", "YTw-OmE_")] + [InlineData("Hell", "SGVsbA")] + [InlineData("Hello", "SGVsbG8")] public async Task Base64UrlSafeEncode(string value, string expected) { // Arrange @@ -145,6 +151,8 @@ public async Task Base64UrlSafeEncode(string value, string expected) [Theory] [InlineData("YTw-OmE_", "a<>:a?")] + [InlineData("SGVsbA", "Hell")] + [InlineData("SGVsbG8", "Hello")] public async Task Base64UrlSafeDecode(string value, string expected) { // Arrange diff --git a/Fluid/Filters/MiscFilters.cs b/Fluid/Filters/MiscFilters.cs index 7a70786e..55734550 100644 --- a/Fluid/Filters/MiscFilters.cs +++ b/Fluid/Filters/MiscFilters.cs @@ -196,6 +196,18 @@ public static ValueTask Base64UrlSafeEncode(FluidValue input, Filter encodedBase64StringBuilder.Replace('+', '-'); encodedBase64StringBuilder.Replace('/', '_'); + if (encodedBase64StringBuilder[^1] == '=') + { + if (encodedBase64StringBuilder[^2] == '=') + { + encodedBase64StringBuilder.Length -= 2; + } + else + { + encodedBase64StringBuilder.Length--; + } + } + return new StringValue(encodedBase64StringBuilder.ToString()); } } @@ -209,13 +221,38 @@ public static ValueTask Base64UrlSafeDecode(FluidValue input, Filter } else { + var paddingCharsToAdd = (value.Length % 4) switch + { + 0 => 0, + 2 => 2, + 3 => 1, + _ => -1 + }; + + if (paddingCharsToAdd == -1) + { + return StringValue.Empty; + } + var encodedBase64StringBuilder = new StringBuilder(value); encodedBase64StringBuilder.Replace('-', '+'); encodedBase64StringBuilder.Replace('_', '/'); - var decodedBase64 = Encoding.UTF8.GetString(Convert.FromBase64String(encodedBase64StringBuilder.ToString())); + // Add the padding characters back. + for (; paddingCharsToAdd > 0; paddingCharsToAdd--) + { + encodedBase64StringBuilder.Append('='); + } - return new StringValue(decodedBase64); + try + { + var decodedBase64 = Encoding.UTF8.GetString(Convert.FromBase64String(encodedBase64StringBuilder.ToString())); + return new StringValue(decodedBase64); + } + catch + { + return StringValue.Empty; + } } }