require 'abstract_unit'
class SanitizersTest < ActionController::TestCase
def setup
@sanitizer = nil # used by assert_sanitizer
end
def test_sanitizer_sanitize_raises_not_implemented_error
assert_raises NotImplementedError do
ActionView::Sanitizer.new.sanitize('')
end
end
def test_sanitizer_remove_xpaths_removes_an_xpath
sanitizer = ActionView::Sanitizer.new
html = %(
hello
)
assert_equal %(hello
), sanitizer.remove_xpaths(html, %w(.//script))
end
def test_sanitizer_remove_xpaths_removes_all_occurences_of_xpath
sanitizer = ActionView::Sanitizer.new
html = %()
assert_equal %(), sanitizer.remove_xpaths(html, %w(.//script))
end
def test_sanitizer_remove_xpaths_not_enumerable_xpaths_parameter
sanitizer = ActionView::Sanitizer.new
assert_raises NoMethodError do
sanitizer.remove_xpaths('hello', './not_enumerable')
end
end
def test_sanitizer_remove_xpaths_faulty_xpath
sanitizer = ActionView::Sanitizer.new
assert_raises Nokogiri::XML::XPath::SyntaxError do
sanitizer.remove_xpaths('hello', %w(..faulty_xpath))
end
end
def test_strip_tags_with_quote
sanitizer = ActionView::FullSanitizer.new
string = '<"
hi'
assert_equal ' hi', sanitizer.sanitize(string)
end
def test_strip_tags_pending
skip "Pending. These methods don't pass."
sanitizer = ActionView::FullSanitizer.new
# Loofah doesn't see any elements in this
# Actual: ""
assert_equal("<<"))
# Actual: "Weia onclick='alert(document.cookie);'/>rdos"
assert_equal("Weirdos", sanitizer.sanitize("Wei<a onclick='alert(document.cookie);'/>rdos"))
# Loofah strips newlines.
# Actual: "This is a test.It no longer contains any HTML."
assert_equal(
%{This is a test.\n\n\nIt no longer contains any HTML.\n}, sanitizer.sanitize(
%{This is a test.\n\n\n\nIt no longer contains any HTML.
\n}))
# Removes comment.
# Actual: "This is "
assert_equal "This is <-- not\n a comment here.", sanitizer.sanitize("This is <-- not\n a comment here.")
# Leaves part of a CDATA section
# Actual: "This has a ]]> here."
assert_equal "This has a here.", sanitizer.sanitize("This has a ]]> here.")
# Actual: "This has an unclosed ]] here..."
assert_equal "This has an unclosed ", sanitizer.sanitize("This has an unclosed ]] here...")
# Fails on the blank string.
# Actual: ''
[nil, '', ' '].each { |blank| assert_equal blank, sanitizer.sanitize(blank) }
end
def test_strip_tags
sanitizer = ActionView::FullSanitizer.new
assert_equal("Dont touch me", sanitizer.sanitize("Dont touch me"))
assert_equal("This is a test.", sanitizer.sanitize("This is a test.
"))
assert_equal("This is a test.", sanitizer.sanitize("This is a test."))
assert_equal "This has a here.", sanitizer.sanitize("This has a here.")
assert_nothing_raised { sanitizer.sanitize("This is a frozen string with no tags".freeze) }
end
def test_strip_links_pending
skip "Pending. Extracted from test_strip_links."
sanitizer = ActionView::LinkSanitizer.new
# Only one of the a-tags are parsed here
# Actual: "a href='hello'>all day long/a>"
assert_equal "all day long", sanitizer.sanitize("<a href='hello'>all day long</a>")
# Loofah reads this as '' which the LinkSanitizer removes
# Actual: ""
assert_equal "on my mind\nall day long")
assert_equal "0wn3d", sanitizer.sanitize("0wn3d")
assert_equal "Magic", sanitizer.sanitize("Magic")
assert_equal "FrrFox", sanitizer.sanitize("FrrFox")
assert_equal "My mind\nall day long", sanitizer.sanitize("My mind\nall day long")
end
def test_sanitize_form
assert_sanitized "", ''
end
def test_sanitize_plaintext
raw = "foo"
assert_sanitized raw, "foo"
end
def test_sanitize_script
assert_sanitized "a b cd e f", "a b cd e f"
end
def test_sanitize_js_handlers
raw = %{onthis="do that" hello}
assert_sanitized raw, %{onthis="do that" hello}
end
def test_sanitize_javascript_href
raw = %{href="javascript:bang" foo, bar}
assert_sanitized raw, %{href="javascript:bang" foo, bar}
end
def test_sanitize_image_src
raw = %{src="javascript:bang"
foo, bar}
assert_sanitized raw, %{src="javascript:bang"
foo, bar}
end
ActionView::WhiteListSanitizer.allowed_tags.each do |tag_name|
define_method "test_should_allow_#{tag_name}_tag" do
assert_sanitized "start <#{tag_name} title=\"1\" onclick=\"foo\">foo bar baz#{tag_name}> end", %(start <#{tag_name} title="1">foo bar baz#{tag_name}> end)
end
end
def test_should_allow_anchors
assert_sanitized %(), %(baz)
end
def test_video_poster_sanitization
assert_sanitized %(), %()
assert_sanitized %(), %()
end
# RFC 3986, sec 4.2
def test_allow_colons_in_path_component
assert_sanitized("foo")
end
%w(src width height alt).each do |img_attr|
define_method "test_should_allow_image_#{img_attr}_attribute" do
assert_sanitized %(
), %(
)
end
end
def test_should_handle_non_html
assert_sanitized 'abc'
end
def test_should_handle_blank_text
assert_sanitized nil
assert_sanitized ''
end
def test_should_allow_custom_tags
text = "foo"
sanitizer = ActionView::WhiteListSanitizer.new
assert_equal(text, sanitizer.sanitize(text, :tags => %w(u)))
end
def test_should_allow_only_custom_tags
text = "foo with bar"
sanitizer = ActionView::WhiteListSanitizer.new
assert_equal("foo with bar", sanitizer.sanitize(text, :tags => %w(u)))
end
def test_should_allow_custom_tags_with_attributes
text = %(foo
)
sanitizer = ActionView::WhiteListSanitizer.new
assert_equal(text, sanitizer.sanitize(text))
end
def test_should_allow_custom_tags_with_custom_attributes
text = %(Lorem ipsum
)
sanitizer = ActionView::WhiteListSanitizer.new
assert_equal(text, sanitizer.sanitize(text, :attributes => ['foo']))
end
def test_should_raise_argument_error_if_tags_is_not_enumerable
sanitizer = ActionView::WhiteListSanitizer.new
e = assert_raise(ArgumentError) do
sanitizer.sanitize('', :tags => 'foo')
end
assert_equal "You should pass :tags as an Enumerable", e.message
end
def test_should_raise_argument_error_if_attributes_is_not_enumerable
sanitizer = ActionView::WhiteListSanitizer.new
e = assert_raise(ArgumentError) do
sanitizer.sanitize('', :attributes => 'foo')
end
assert_equal "You should pass :attributes as an Enumerable", e.message
end
def test_should_not_accept_non_loofah_inheriting_scrubber
sanitizer = ActionView::WhiteListSanitizer.new
scrubber = Object.new
scrubber.class_eval do
def scrub(node); node.name = 'h1'; end
end
assert_raise Loofah::ScrubberNotFound do
sanitizer.sanitize('', :scrubber => scrubber)
end
end
def test_should_accept_loofah_inheriting_scrubber
sanitizer = ActionView::WhiteListSanitizer.new
scrubber = Loofah::Scrubber.new
scrubber.class_eval do
def scrub(node); node.name = 'h1'; end
end
html = ""
assert_equal "hello!
", sanitizer.sanitize(html, :scrubber => scrubber)
end
def test_should_accept_loofah_scrubber_that_wraps_a_block
sanitizer = ActionView::WhiteListSanitizer.new
scrubber = Loofah::Scrubber.new { |node| node.name = 'h1' }
html = ""
assert_equal "hello!
", sanitizer.sanitize(html, :scrubber => scrubber)
end
def test_custom_scrubber_takes_precedence_over_other_options
sanitizer = ActionView::WhiteListSanitizer.new
scrubber = Loofah::Scrubber.new { |node| node.name = 'h1' }
html = ""
assert_equal "hello!
", sanitizer.sanitize(html, :scrubber => scrubber, :tags => ['foo'])
end
[%w(img src), %w(a href)].each do |(tag, attr)|
define_method "test_should_strip_#{attr}_attribute_in_#{tag}_with_bad_protocols" do
assert_sanitized %(<#{tag} #{attr}="javascript:bang" title="1">boo#{tag}>), %(<#{tag} title="1">boo#{tag}>)
end
end
def test_should_block_script_tag
assert_sanitized %(), ""
end
def test_should_not_fall_for_xss_image_hack_pending
skip "Pending."
# Actual: "
alert(\"XSS\")\">"
assert_sanitized %(
">), "
"
end
[%(
),
%(
),
%(
),
%(
),
%(
),
%(
),
%(
),
%(
),
%(
),
%(
),
%(
),
%(
),
%(
),
%(
),
%(
)].each_with_index do |img_hack, i|
define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do
assert_sanitized img_hack, "
"
end
end
def test_should_sanitize_tag_broken_up_by_null
skip "Pending."
# Loofah parses this to an tag and removes it.
# So actual is an empty string"
assert_sanitized %(alert(\"XSS\")), "alert(\"XSS\")"
end
def test_should_sanitize_invalid_script_tag
assert_sanitized %(), ""
end
def test_should_sanitize_script_tag_with_multiple_open_brackets
skip "Pending."
# Actual: "alert(\"XSS\");//"
assert_sanitized %(<), "<"
# Actual: ""
assert_sanitized %(