diff --git a/History.md b/History.md index 97c8866..507a4a2 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,9 @@ ## 5.0.2 (unreleased) +### Features +* Add `base64_encode`, `base64_decode`, `base64_url_safe_encode`, and `base64_url_safe_decode` filters (#1450) [Daniel Insley] + ### Fixes * Fix support for using a String subclass for the liquid source (#1421) [Dylan Thacker-Smith] diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb index 150406a..e7ae5d4 100644 --- a/lib/liquid/standardfilters.rb +++ b/lib/liquid/standardfilters.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'cgi' +require 'base64' require 'bigdecimal' module Liquid @@ -63,6 +64,26 @@ module Liquid result end + def base64_encode(input) + Base64.strict_encode64(input.to_s) + end + + def base64_decode(input) + Base64.strict_decode64(input.to_s) + rescue ::ArgumentError + raise Liquid::ArgumentError, "invalid base64 provided to base64_decode" + end + + def base64_url_safe_encode(input) + Base64.urlsafe_encode64(input.to_s) + end + + def base64_url_safe_decode(input) + Base64.urlsafe_decode64(input.to_s) + rescue ::ArgumentError + raise Liquid::ArgumentError, "invalid base64 provided to base64_url_safe_decode" + end + def slice(input, offset, length = nil) offset = Utils.to_integer(offset) length = length ? Utils.to_integer(length) : 1 diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb index a2456fd..0962476 100644 --- a/test/integration/standard_filter_test.rb +++ b/test/integration/standard_filter_test.rb @@ -145,6 +145,40 @@ class StandardFiltersTest < Minitest::Test assert_equal('<strong>Hulk</strong>', @filters.escape_once('<strong>Hulk')) end + def test_base64_encode + assert_equal('b25lIHR3byB0aHJlZQ==', @filters.base64_encode('one two three')) + assert_equal('', @filters.base64_encode(nil)) + end + + def test_base64_decode + assert_equal('one two three', @filters.base64_decode('b25lIHR3byB0aHJlZQ==')) + + exception = assert_raises(Liquid::ArgumentError) do + @filters.base64_decode("invalidbase64") + end + + assert_equal('Liquid error: invalid base64 provided to base64_decode', exception.message) + end + + def test_base64_url_safe_encode + assert_equal( + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8', + @filters.base64_url_safe_encode('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*()-=_+/?.:;[]{}\|') + ) + assert_equal('', @filters.base64_url_safe_encode(nil)) + end + + def test_base64_url_safe_decode + assert_equal( + 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*()-=_+/?.:;[]{}\|', + @filters.base64_url_safe_decode('YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8') + ) + exception = assert_raises(Liquid::ArgumentError) do + @filters.base64_url_safe_decode("invalidbase64") + end + assert_equal('Liquid error: invalid base64 provided to base64_url_safe_decode', exception.message) + end + def test_url_encode assert_equal('foo%2B1%40example.com', @filters.url_encode('foo+1@example.com')) assert_equal('1', @filters.url_encode(1))