From cc47fa8f03f923c9e924a39e11cc45c9e9cc2f51 Mon Sep 17 00:00:00 2001 From: Guillaume Malette Date: Fri, 29 Sep 2023 09:39:59 -0400 Subject: [PATCH] [base64] Respect string encoding of input in base64_decode filters --- lib/liquid/standardfilters.rb | 19 ++++++++++++++++-- test/integration/standard_filter_test.rb | 25 ++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb index 661235a9..41cae30f 100644 --- a/lib/liquid/standardfilters.rb +++ b/lib/liquid/standardfilters.rb @@ -29,6 +29,19 @@ module Liquid ) STRIP_HTML_TAGS = /<.*?>/m + class << self + def try_coerce_encoding(input, encoding:) + original_encoding = input.encoding + if input.encoding != encoding + input.force_encoding(encoding) + if !input.valid_encoding? + input.force_encoding(original_encoding) + end + end + input + end + end + # @liquid_public_docs # @liquid_type filter # @liquid_category array @@ -150,7 +163,8 @@ module Liquid # @liquid_syntax string | base64_decode # @liquid_return [string] def base64_decode(input) - Base64.strict_decode64(input.to_s) + input = input.to_s + StandardFilters.try_coerce_encoding(Base64.strict_decode64(input), encoding: input.encoding) rescue ::ArgumentError raise Liquid::ArgumentError, "invalid base64 provided to base64_decode" end @@ -174,7 +188,8 @@ module Liquid # @liquid_syntax string | base64_url_safe_decode # @liquid_return [string] def base64_url_safe_decode(input) - Base64.urlsafe_decode64(input.to_s) + input = input.to_s + StandardFilters.try_coerce_encoding(Base64.urlsafe_decode64(input), encoding: input.encoding) rescue ::ArgumentError raise Liquid::ArgumentError, "invalid base64 provided to base64_url_safe_decode" end diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb index b2405f7f..7e7c3486 100644 --- a/test/integration/standard_filter_test.rb +++ b/test/integration/standard_filter_test.rb @@ -176,7 +176,17 @@ class StandardFiltersTest < Minitest::Test end def test_base64_decode - assert_equal('one two three', @filters.base64_decode('b25lIHR3byB0aHJlZQ==')) + decoded = @filters.base64_decode('b25lIHR3byB0aHJlZQ==') + assert_equal('one two three', decoded) + assert_equal(Encoding::UTF_8, decoded.encoding) + + decoded = @filters.base64_decode('4pyF') + assert_equal('✅', decoded) + assert_equal(Encoding::UTF_8, decoded.encoding) + + decoded = @filters.base64_decode("/w==") + assert_equal(Encoding::ASCII_8BIT, decoded.encoding) + assert_equal((+"\xFF").force_encoding(Encoding::ASCII_8BIT), decoded) exception = assert_raises(Liquid::ArgumentError) do @filters.base64_decode("invalidbase64") @@ -194,10 +204,21 @@ class StandardFiltersTest < Minitest::Test end def test_base64_url_safe_decode + decoded = @filters.base64_url_safe_decode('YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8') assert_equal( 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*()-=_+/?.:;[]{}\|', - @filters.base64_url_safe_decode('YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8'), + decoded, ) + assert_equal(Encoding::UTF_8, decoded.encoding) + + decoded = @filters.base64_url_safe_decode('4pyF') + assert_equal('✅', decoded) + assert_equal(Encoding::UTF_8, decoded.encoding) + + decoded = @filters.base64_url_safe_decode("_w==") + assert_equal(Encoding::ASCII_8BIT, decoded.encoding) + assert_equal((+"\xFF").force_encoding(Encoding::ASCII_8BIT), decoded) + exception = assert_raises(Liquid::ArgumentError) do @filters.base64_url_safe_decode("invalidbase64") end