diff --git a/lib/haml/helpers/action_view_mods.rb b/lib/haml/helpers/action_view_mods.rb index 8bafa325..a05373ff 100644 --- a/lib/haml/helpers/action_view_mods.rb +++ b/lib/haml/helpers/action_view_mods.rb @@ -26,7 +26,8 @@ module ActionView def set_output_buffer_with_haml(new) if is_haml? - new = String.new(new) if Haml::Util.rails_xss_safe? && new.is_a?(ActionView::SafeBuffer) + new = String.new(new) if Haml::Util.rails_xss_safe? && + new.is_a?(Haml::Util.rails_safe_buffer_class) haml_buffer.buffer = new else set_output_buffer_without_haml new diff --git a/lib/haml/helpers/xss_mods.rb b/lib/haml/helpers/xss_mods.rb index e5b25285..38aaa4e5 100644 --- a/lib/haml/helpers/xss_mods.rb +++ b/lib/haml/helpers/xss_mods.rb @@ -19,45 +19,46 @@ module Haml def html_escape_with_haml_xss(text) str = text.to_s return text if str.html_safe? - html_escape_without_haml_xss(str).html_safe! + Haml::Util.html_safe(html_escape_without_haml_xss(str)) end # Output is always HTML safe def find_and_preserve_with_haml_xss(*args, &block) - find_and_preserve_without_haml_xss(*args, &block).html_safe! + Haml::Util.html_safe(find_and_preserve_without_haml_xss(*args, &block)) end # Output is always HTML safe def preserve_with_haml_xss(*args, &block) - preserve_without_haml_xss(*args, &block).html_safe! + Haml::Util.html_safe(preserve_without_haml_xss(*args, &block)) end # Output is always HTML safe def list_of_with_haml_xss(*args, &block) - list_of_without_haml_xss(*args, &block).html_safe! + Haml::Util.html_safe(list_of_without_haml_xss(*args, &block)) end # Input is escaped, output is always HTML safe def surround_with_haml_xss(front, back = front, &block) - surround_without_haml_xss( - haml_xss_html_escape(front), - haml_xss_html_escape(back), - &block).html_safe! + Haml::Util.html_safe( + surround_without_haml_xss( + haml_xss_html_escape(front), + haml_xss_html_escape(back), + &block)) end # Input is escaped, output is always HTML safe def precede_with_haml_xss(str, &block) - precede_without_haml_xss(haml_xss_html_escape(str), &block).html_safe! + Haml::Util.html_safe(precede_without_haml_xss(haml_xss_html_escape(str), &block)) end # Input is escaped, output is always HTML safe def succeed_with_haml_xss(str, &block) - succeed_without_haml_xss(haml_xss_html_escape(str), &block).html_safe! + Haml::Util.html_safe(succeed_without_haml_xss(haml_xss_html_escape(str), &block)) end # Output is always HTML safe def capture_haml_with_haml_xss(*args, &block) - capture_haml_without_haml_xss(*args, &block).html_safe! + Haml::Util.html_safe(capture_haml_without_haml_xss(*args, &block)) end # Input is escaped @@ -67,7 +68,7 @@ module Haml # Output is always HTML safe def haml_indent_with_haml_xss - haml_indent_without_haml_xss.html_safe! + Haml::Util.html_safe(haml_indent_without_haml_xss) end # Input is escaped, haml_concat'ed output is always HTML safe @@ -79,7 +80,7 @@ module Haml # Output is always HTML safe def escape_once_with_haml_xss(*args) - escape_once_without_haml_xss(*args).html_safe! + Haml::Util.html_safe(escape_once_without_haml_xss(*args)) end private diff --git a/lib/haml/template.rb b/lib/haml/template.rb index 6455ada3..b738c320 100644 --- a/lib/haml/template.rb +++ b/lib/haml/template.rb @@ -28,7 +28,7 @@ module Haml Haml::Precompiler.module_eval do def precompiled_method_return_value_with_haml_xss - "(#{precompiled_method_return_value_without_haml_xss}).html_safe!" + "::Haml::Util.html_safe(#{precompiled_method_return_value_without_haml_xss})" end alias_method :precompiled_method_return_value_without_haml_xss, :precompiled_method_return_value alias_method :precompiled_method_return_value, :precompiled_method_return_value_with_haml_xss diff --git a/lib/haml/util.rb b/lib/haml/util.rb index 16b2f5b4..ec2b112e 100644 --- a/lib/haml/util.rb +++ b/lib/haml/util.rb @@ -181,6 +181,17 @@ module Haml false end + # Returns the given text, marked as being HTML-safe. + # With older versions of the Rails XSS-safety mechanism, + # this destructively modifies the HTML-safety of `text`. + # + # @param text [String] + # @return [String] `text`, marked as HTML-safe + def html_safe(text) + return text.html_safe if defined?(ActiveSupport::SafeBuffer) + text.html_safe! + end + # Assert that a given object (usually a String) is HTML safe # according to Rails' XSS handling, if it's loaded. # @@ -190,6 +201,11 @@ module Haml raise Haml::Error.new("Expected #{text.inspect} to be HTML-safe.") end + def rails_safe_buffer_class + return ActionView::SafeBuffer if defined?(ActionView::SafeBuffer) + ActiveSupport::SafeBuffer + end + ## Cross-Ruby-Version Compatibility # Whether or not this is running under Ruby 1.8 or lower. diff --git a/test/haml/template_test.rb b/test/haml/template_test.rb index e813ee9b..ccc2078b 100755 --- a/test/haml/template_test.rb +++ b/test/haml/template_test.rb @@ -258,7 +258,7 @@ END end def test_xss_protection_with_safe_strings - assert_equal("Foo & Bar\n", render('= "Foo & Bar".html_safe!', :action_view)) + assert_equal("Foo & Bar\n", render('= Haml::Util.html_safe("Foo & Bar")', :action_view)) end def test_xss_protection_with_bang @@ -274,11 +274,11 @@ END end def test_xss_protection_with_safe_strings_in_interpolation - assert_equal("Foo & Bar\n", render('Foo #{"&".html_safe!} Bar', :action_view)) + assert_equal("Foo & Bar\n", render('Foo #{Haml::Util.html_safe("&")} Bar', :action_view)) end def test_xss_protection_with_mixed_strings_in_interpolation - assert_equal("Foo & Bar & Baz\n", render('Foo #{"&".html_safe!} Bar #{"&"} Baz', :action_view)) + assert_equal("Foo & Bar & Baz\n", render('Foo #{Haml::Util.html_safe("&")} Bar #{"&"} Baz', :action_view)) end def test_rendered_string_is_html_safe