require 'test_helper' require 'better_html/test_helper/safe_erb/tag_interpolation' module BetterHtml module TestHelper module SafeErb class TagInterpolationTest < ActiveSupport::TestCase setup do @config = BetterHtml::Config.new( javascript_safe_methods: ['j', 'escape_javascript', 'to_json'], javascript_attribute_names: [/\Aon/i, 'data-eval'], ) end test "raw in EOF assert_equal 0, errors.size end test "raw in EOF assert_equal 0, errors.size end test "html_safe in EOF assert_equal 0, errors.size end test "<%== in EOF assert_equal 0, errors.size end test "string without interpolation is safe" do errors = validate(<<-EOF).errors ')"> EOF assert_equal 0, errors.size end test "string with interpolation" do errors = validate(<<-EOF).errors "> EOF assert_equal 1, errors.size assert_equal 'name', errors.first.location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message end test "string with interpolation and ternary" do errors = validate(<<-EOF).errors "> EOF assert_equal 2, errors.size assert_equal 'bar', errors[0].location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors[0].message assert_equal 'baz', errors[1].location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors[1].message end test "plain erb tag in html attribute" do errors = validate(<<-EOF).errors EOF assert_equal 1, errors.size assert_equal 'unsafe', errors.first.location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message end test "to_json is safe in html attribute" do errors = validate(<<-EOF).errors EOF assert_predicate errors, :empty? end test "ternary with safe javascript escaping" do errors = validate(<<-EOF).errors EOF assert_predicate errors, :empty? end test "ternary with unsafe javascript escaping" do errors = validate(<<-EOF).errors EOF assert_equal 1, errors.size assert_equal 'bar', errors.first.location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message end test "j is safe in html attribute" do errors = validate(<<-EOF).errors EOF assert_predicate errors, :empty? end test "j() is safe in html attribute" do errors = validate(<<-EOF).errors EOF assert_predicate errors, :empty? end test "escape_javascript is safe in html attribute" do errors = validate(<<-EOF).errors EOF assert_predicate errors, :empty? end test "escape_javascript() is safe in html attribute" do errors = validate(<<-EOF).errors EOF assert_predicate errors, :empty? end test "html_safe is never safe in html attribute, even non javascript attributes like href" do errors = validate(<<-EOF).errors EOF assert_equal 1, errors.size assert_equal 'unsafe.html_safe', errors.first.location.source assert_equal "erb interpolation with '<%= (...).html_safe %>' in this context is never safe", errors.first.message end test "html_safe is never safe in html attribute, even with to_json" do errors = validate(<<-EOF).errors EOF assert_equal 2, errors.size assert_equal 'unsafe.to_json.html_safe', errors[0].location.source assert_equal "erb interpolation with '<%= (...).html_safe %>' in this context is never safe", errors[0].message assert_equal 'unsafe.to_json.html_safe', errors[1].location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors[1].message end test "<%== is never safe in html attribute, even non javascript attributes like href" do errors = validate(<<-EOF).errors EOF assert_equal 1, errors.size assert_equal '<%== unsafe %>', errors.first.location.source assert_includes "erb interpolation with '<%==' inside html attribute is never safe", errors.first.message end test "<%== is never safe in html attribute, even with to_json" do errors = validate(<<-EOF).errors EOF assert_equal 1, errors.size assert_equal '<%== unsafe.to_json %>', errors.first.location.source assert_includes "erb interpolation with '<%==' inside html attribute is never safe", errors.first.message end test "raw is never safe in html attribute, even non javascript attributes like href" do errors = validate(<<-EOF).errors EOF assert_equal 1, errors.size assert_equal 'raw unsafe', errors.first.location.source assert_equal "erb interpolation with '<%= raw(...) %>' in this context is never safe", errors.first.message end test "raw is never safe in html attribute, even with to_json" do errors = validate(<<-EOF).errors EOF assert_equal 2, errors.size assert_equal 'raw unsafe.to_json', errors[0].location.source assert_equal "erb interpolation with '<%= raw(...) %>' in this context is never safe", errors[0].message assert_equal 'raw unsafe.to_json', errors[1].location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors[1].message end test "unsafe javascript methods in helper calls with new hash syntax" do errors = validate(<<-EOF).errors <%= ui_my_helper(:foo, onclick: "alert(\#{unsafe})", onmouseover: "alert(\#{unsafe.to_json})") %> EOF assert_equal 1, errors.size assert_equal "unsafe", errors[0].location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors[0].message end test "unsafe javascript methods in helper calls with old hash syntax" do errors = validate(<<-EOF).errors <%= ui_my_helper(:foo, :onclick => "alert(\#{unsafe})") %> EOF assert_equal 1, errors.size assert_equal "unsafe", errors.first.location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message end test "unsafe javascript methods in helper calls with more than one level of nested hash and :dstr" do errors = validate(<<-EOF).errors <%= ui_my_helper(:foo, inner_html: { onclick: "foo \#{unsafe}" }) %> EOF assert_equal 1, errors.size assert_equal "unsafe", errors.first.location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message end test "safe javascript methods in helper calls with more than one level of nested hash and :dstr" do errors = validate(<<-EOF).errors <%= ui_my_helper(:foo, inner_html: { onclick: "foo \#{unsafe.to_json}" }) %> EOF assert_equal 0, errors.size end test "unsafe javascript methods in helper calls with string as key" do errors = validate(<<-EOF).errors <%= ui_my_helper(:foo, 'data-eval' => "alert(\#{unsafe})") %> EOF assert_equal 1, errors.size assert_equal "unsafe", errors.first.location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message end test "unsafe javascript methods in helper calls with nested data key" do errors = validate(<<-EOF).errors <%= ui_my_helper(:foo, data: { eval: "alert(\#{unsafe})" }) %> EOF assert_equal 1, errors.size assert_equal "unsafe", errors.first.location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message end test "unsafe javascript methods in helper calls with more than one level of nested data key" do errors = validate(<<-EOF).errors <%= ui_my_helper(:foo, inner_html: { data: { eval: "alert(\#{unsafe})" } }) %> EOF assert_equal 1, errors.size assert_equal "unsafe", errors.first.location.source assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message end test "using raw anywhere in helpers" do errors = validate(<<-EOF).errors <%= ui_my_helper(:foo, help_text: raw("foo")) %> EOF assert_equal 1, errors.size assert_equal "ui_my_helper(:foo, help_text: raw(\"foo\"))", errors.first.location.source assert_equal "erb interpolation with '<%= raw(...) %>' in this context is never safe", errors.first.message end test "using raw anywhere in html tags" do errors = validate(<<-EOF).errors "> EOF assert_equal 1, errors.size assert_equal "raw(\"hello\")", errors.first.location.source assert_equal "erb interpolation with '<%= raw(...) %>' in this context is never safe", errors.first.message end private def validate(data, template_language: :html) parser = BetterHtml::Parser.new(data, template_language: template_language) tester = BetterHtml::TestHelper::SafeErb::TagInterpolation.new(parser, config: @config) tester.validate tester end end end end end