mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Makes text_helper methods sanitize the input if the input is not safe or :safe => true option is not provided
This commit is contained in:
parent
399b493cb4
commit
ab764ecbfe
2 changed files with 118 additions and 22 deletions
|
@ -74,6 +74,7 @@ module ActionView
|
||||||
|
|
||||||
options.reverse_merge!(:length => 30)
|
options.reverse_merge!(:length => 30)
|
||||||
|
|
||||||
|
text = sanitize(text) unless text.html_safe? || options[:safe]
|
||||||
text.truncate(options.delete(:length), options) if text
|
text.truncate(options.delete(:length), options) if text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -105,6 +106,7 @@ module ActionView
|
||||||
end
|
end
|
||||||
options.reverse_merge!(:highlighter => '<strong class="highlight">\1</strong>')
|
options.reverse_merge!(:highlighter => '<strong class="highlight">\1</strong>')
|
||||||
|
|
||||||
|
text = sanitize(text) unless text.html_safe? || options[:safe]
|
||||||
if text.blank? || phrases.blank?
|
if text.blank? || phrases.blank?
|
||||||
text
|
text
|
||||||
else
|
else
|
||||||
|
@ -244,13 +246,14 @@ module ActionView
|
||||||
#
|
#
|
||||||
def textilize(text, *options)
|
def textilize(text, *options)
|
||||||
options ||= [:hard_breaks]
|
options ||= [:hard_breaks]
|
||||||
|
text = sanitize(text) unless text.html_safe? || options.delete(:safe)
|
||||||
|
|
||||||
if text.blank?
|
if text.blank?
|
||||||
""
|
""
|
||||||
else
|
else
|
||||||
textilized = RedCloth.new(text, options)
|
textilized = RedCloth.new(text, options)
|
||||||
textilized.to_html
|
textilized.to_html
|
||||||
end
|
end.html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the text with all the Textile codes turned into HTML tags,
|
# Returns the text with all the Textile codes turned into HTML tags,
|
||||||
|
@ -271,8 +274,8 @@ module ActionView
|
||||||
#
|
#
|
||||||
# textilize_without_paragraph("Visit the Rails website "here":http://www.rubyonrails.org/.)
|
# textilize_without_paragraph("Visit the Rails website "here":http://www.rubyonrails.org/.)
|
||||||
# # => "Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>."
|
# # => "Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>."
|
||||||
def textilize_without_paragraph(text)
|
def textilize_without_paragraph(text, *options)
|
||||||
textiled = textilize(text)
|
textiled = textilize(text, options)
|
||||||
if textiled[0..2] == "<p>" then textiled = textiled[3..-1] end
|
if textiled[0..2] == "<p>" then textiled = textiled[3..-1] end
|
||||||
if textiled[-4..-1] == "</p>" then textiled = textiled[0..-5] end
|
if textiled[-4..-1] == "</p>" then textiled = textiled[0..-5] end
|
||||||
return textiled
|
return textiled
|
||||||
|
@ -295,8 +298,9 @@ module ActionView
|
||||||
#
|
#
|
||||||
# markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")')
|
# markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")')
|
||||||
# # => '<p><img src="http://rubyonrails.com/images/rails.png" alt="The ROR logo" title="Ruby on Rails" /></p>'
|
# # => '<p><img src="http://rubyonrails.com/images/rails.png" alt="The ROR logo" title="Ruby on Rails" /></p>'
|
||||||
def markdown(text)
|
def markdown(text, options = {})
|
||||||
text.blank? ? "" : BlueCloth.new(text).to_html
|
text = sanitize(text) unless options[:safe]
|
||||||
|
(text.blank? ? "" : BlueCloth.new(text).to_html).html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns +text+ transformed into HTML using simple formatting rules.
|
# Returns +text+ transformed into HTML using simple formatting rules.
|
||||||
|
@ -320,14 +324,15 @@ module ActionView
|
||||||
#
|
#
|
||||||
# simple_format("Look ma! A class!", :class => 'description')
|
# simple_format("Look ma! A class!", :class => 'description')
|
||||||
# # => "<p class='description'>Look ma! A class!</p>"
|
# # => "<p class='description'>Look ma! A class!</p>"
|
||||||
def simple_format(text, html_options={})
|
def simple_format(text, html_options={}, options={})
|
||||||
|
text = '' if text.nil?
|
||||||
start_tag = tag('p', html_options, true)
|
start_tag = tag('p', html_options, true)
|
||||||
text = h(text)
|
text = sanitize(text) unless text.html_safe? || options[:safe]
|
||||||
text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
|
text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
|
||||||
text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
|
text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
|
||||||
text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
|
text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
|
||||||
text.insert 0, start_tag
|
text.insert 0, start_tag
|
||||||
text.safe_concat("</p>")
|
text.html_safe.safe_concat("</p>")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
|
# Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
|
||||||
|
@ -368,7 +373,7 @@ module ActionView
|
||||||
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>.
|
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>.
|
||||||
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
|
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
|
||||||
def auto_link(text, *args, &block)#link = :all, html = {}, &block)
|
def auto_link(text, *args, &block)#link = :all, html = {}, &block)
|
||||||
return '' if text.blank?
|
return ''.html_safe if text.blank?
|
||||||
|
|
||||||
options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
|
options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
|
||||||
unless args.empty?
|
unless args.empty?
|
||||||
|
@ -378,9 +383,9 @@ module ActionView
|
||||||
options.reverse_merge!(:link => :all, :html => {})
|
options.reverse_merge!(:link => :all, :html => {})
|
||||||
|
|
||||||
case options[:link].to_sym
|
case options[:link].to_sym
|
||||||
when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], &block), options[:html], &block)
|
when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], options, &block), options[:html], &block)
|
||||||
when :email_addresses then auto_link_email_addresses(text, options[:html], &block)
|
when :email_addresses then auto_link_email_addresses(text, options[:html], &block)
|
||||||
when :urls then auto_link_urls(text, options[:html], &block)
|
when :urls then auto_link_urls(text, options[:html], options, &block)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -544,7 +549,7 @@ module ActionView
|
||||||
|
|
||||||
# Turns all urls into clickable links. If a block is given, each url
|
# Turns all urls into clickable links. If a block is given, each url
|
||||||
# is yielded and the result is used as the link text.
|
# is yielded and the result is used as the link text.
|
||||||
def auto_link_urls(text, html_options = {})
|
def auto_link_urls(text, html_options = {}, options = {})
|
||||||
link_attributes = html_options.stringify_keys
|
link_attributes = html_options.stringify_keys
|
||||||
text.gsub(AUTO_LINK_RE) do
|
text.gsub(AUTO_LINK_RE) do
|
||||||
scheme, href = $1, $&
|
scheme, href = $1, $&
|
||||||
|
@ -566,21 +571,22 @@ module ActionView
|
||||||
link_text = block_given?? yield(href) : href
|
link_text = block_given?? yield(href) : href
|
||||||
href = 'http://' + href unless scheme
|
href = 'http://' + href unless scheme
|
||||||
|
|
||||||
content_tag(:a, link_text, link_attributes.merge('href' => href)) + punctuation.reverse.join('')
|
content_tag(:a, link_text, link_attributes.merge('href' => href), !(options[:safe] || text.html_safe?)) + punctuation.reverse.join('')
|
||||||
end
|
end
|
||||||
end
|
end.html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
# Turns all email addresses into clickable links. If a block is given,
|
# Turns all email addresses into clickable links. If a block is given,
|
||||||
# each email is yielded and the result is used as the link text.
|
# each email is yielded and the result is used as the link text.
|
||||||
def auto_link_email_addresses(text, html_options = {})
|
def auto_link_email_addresses(text, html_options = {}, options = {})
|
||||||
text.gsub(AUTO_EMAIL_RE) do
|
text.gsub(AUTO_EMAIL_RE) do
|
||||||
text = $&
|
text = $&
|
||||||
|
|
||||||
if auto_linked?($`, $')
|
if auto_linked?($`, $')
|
||||||
text
|
text.html_safe
|
||||||
else
|
else
|
||||||
display_text = (block_given?) ? yield(text) : text
|
display_text = (block_given?) ? yield(text) : text
|
||||||
|
display_text = sanitize(display_text) unless options[:safe]
|
||||||
mail_to text, display_text, html_options
|
mail_to text, display_text, html_options
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,19 +45,42 @@ class TextHelperTest < ActionView::TestCase
|
||||||
assert simple_format("<b> test with html tags </b>").html_safe?
|
assert simple_format("<b> test with html tags </b>").html_safe?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_simple_format_should_escape_unsafe_input
|
def test_simple_format_should_sanitize_unsafe_input
|
||||||
assert_equal "<p><b> test with unsafe string </b></p>", simple_format("<b> test with unsafe string </b>")
|
assert_equal "<p><b> test with unsafe string </b></p>", simple_format("<b> test with unsafe string </b><script>code!</script>")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_simple_format_should_not_escape_safe_input
|
def test_simple_format_should_not_sanitize_input_if_safe_option
|
||||||
|
assert_equal "<p><b> test with unsafe string </b><script>code!</script></p>", simple_format("<b> test with unsafe string </b><script>code!</script>", {}, :safe => true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_simple_format_should_not_sanitize_safe_input
|
||||||
assert_equal "<p><b> test with safe string </b></p>", simple_format("<b> test with safe string </b>".html_safe)
|
assert_equal "<p><b> test with safe string </b></p>", simple_format("<b> test with safe string </b>".html_safe)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_truncate_should_be_html_safe
|
||||||
|
assert truncate("Hello World!", :length => 12).html_safe?
|
||||||
|
end
|
||||||
|
|
||||||
def test_truncate
|
def test_truncate
|
||||||
assert_equal "Hello World!", truncate("Hello World!", :length => 12)
|
assert_equal "Hello World!", truncate("Hello World!", :length => 12)
|
||||||
assert_equal "Hello Wor...", truncate("Hello World!!", :length => 12)
|
assert_equal "Hello Wor...", truncate("Hello World!!", :length => 12)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_truncate_should_sanitize_unsafe_input
|
||||||
|
assert_equal "Hello World!", truncate("Hello <script>code!</script>World!", :length => 12)
|
||||||
|
assert_equal "Hello Wor...", truncate("Hello <script>code!</script>World!!", :length => 12)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_truncate_should_not_sanitize_input_if_safe_option
|
||||||
|
assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!", :length => 12, :safe => true)
|
||||||
|
assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!!", :length => 12, :safe => true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_truncate_should_not_sanitize_safe_input
|
||||||
|
assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!".html_safe, :length => 12)
|
||||||
|
assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!!".html_safe, :length => 12)
|
||||||
|
end
|
||||||
|
|
||||||
def test_truncate_should_use_default_length_of_30
|
def test_truncate_should_use_default_length_of_30
|
||||||
str = "This is a string that will go longer then the default truncate length of 30"
|
str = "This is a string that will go longer then the default truncate length of 30"
|
||||||
assert_equal str[0...27] + "...", truncate(str)
|
assert_equal str[0...27] + "...", truncate(str)
|
||||||
|
@ -93,7 +116,11 @@ class TextHelperTest < ActionView::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_highlighter
|
def test_highlight_should_be_html_safe
|
||||||
|
assert highlight("This is a beautiful morning", "beautiful").html_safe?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_highlight
|
||||||
assert_equal(
|
assert_equal(
|
||||||
"This is a <strong class=\"highlight\">beautiful</strong> morning",
|
"This is a <strong class=\"highlight\">beautiful</strong> morning",
|
||||||
highlight("This is a beautiful morning", "beautiful")
|
highlight("This is a beautiful morning", "beautiful")
|
||||||
|
@ -117,6 +144,27 @@ class TextHelperTest < ActionView::TestCase
|
||||||
assert_equal ' ', highlight(' ', 'blank text is returned verbatim')
|
assert_equal ' ', highlight(' ', 'blank text is returned verbatim')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_highlight_should_sanitize_unsafe_input
|
||||||
|
assert_equal(
|
||||||
|
"This is a <strong class=\"highlight\">beautiful</strong> morning",
|
||||||
|
highlight("This is a beautiful morning<script>code!</script>", "beautiful")
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_highlight_should_not_sanitize_input_if_safe_option
|
||||||
|
assert_equal(
|
||||||
|
"This is a <strong class=\"highlight\">beautiful</strong> morning<script>code!</script>",
|
||||||
|
highlight("This is a beautiful morning<script>code!</script>", "beautiful", :safe => true)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_highlight_should_not_sanitize_safe_input
|
||||||
|
assert_equal(
|
||||||
|
"This is a <strong class=\"highlight\">beautiful</strong> morning<script>code!</script>",
|
||||||
|
highlight("This is a beautiful morning<script>code!</script>".html_safe, "beautiful")
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def test_highlight_with_regexp
|
def test_highlight_with_regexp
|
||||||
assert_equal(
|
assert_equal(
|
||||||
"This is a <strong class=\"highlight\">beautiful!</strong> morning",
|
"This is a <strong class=\"highlight\">beautiful!</strong> morning",
|
||||||
|
@ -163,7 +211,7 @@ class TextHelperTest < ActionView::TestCase
|
||||||
highlight("<p class=\"beautiful\">This is a beautiful morning, but also a beautiful day</p>", "beautiful")
|
highlight("<p class=\"beautiful\">This is a beautiful morning, but also a beautiful day</p>", "beautiful")
|
||||||
)
|
)
|
||||||
assert_equal(
|
assert_equal(
|
||||||
"<p>This is a <strong class=\"highlight\">beautiful</strong> <a href=\"http://example.com/beautiful\#top?what=beautiful%20morning&when=now+then\">morning</a>, but also a <strong class=\"highlight\">beautiful</strong> day</p>",
|
"<p>This is a <strong class=\"highlight\">beautiful</strong> <a href=\"http://example.com/beautiful\#top?what=beautiful%20morning&when=now+then\">morning</a>, but also a <strong class=\"highlight\">beautiful</strong> day</p>",
|
||||||
highlight("<p>This is a beautiful <a href=\"http://example.com/beautiful\#top?what=beautiful%20morning&when=now+then\">morning</a>, but also a beautiful day</p>", "beautiful")
|
highlight("<p>This is a beautiful <a href=\"http://example.com/beautiful\#top?what=beautiful%20morning&when=now+then\">morning</a>, but also a beautiful day</p>", "beautiful")
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -286,7 +334,17 @@ class TextHelperTest < ActionView::TestCase
|
||||||
%{<a href="#{CGI::escapeHTML href}">#{CGI::escapeHTML link_text}</a>}
|
%{<a href="#{CGI::escapeHTML href}">#{CGI::escapeHTML link_text}</a>}
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_auto_linking
|
def test_auto_link_should_be_html_safe
|
||||||
|
email_raw = 'santiago@wyeworks.com'
|
||||||
|
link_raw = 'http://www.rubyonrails.org'
|
||||||
|
|
||||||
|
assert auto_link(nil).html_safe?
|
||||||
|
assert auto_link('').html_safe?
|
||||||
|
assert auto_link("#{link_raw} #{link_raw} #{link_raw}").html_safe?
|
||||||
|
assert auto_link("hello #{email_raw}").html_safe?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_auto_link
|
||||||
email_raw = 'david@loudthinking.com'
|
email_raw = 'david@loudthinking.com'
|
||||||
email_result = %{<a href="mailto:#{email_raw}">#{email_raw}</a>}
|
email_result = %{<a href="mailto:#{email_raw}">#{email_raw}</a>}
|
||||||
link_raw = 'http://www.rubyonrails.com'
|
link_raw = 'http://www.rubyonrails.com'
|
||||||
|
@ -378,6 +436,21 @@ class TextHelperTest < ActionView::TestCase
|
||||||
assert_equal %(<p>#{link10_result} Link</p>), auto_link("<p>#{link10_raw} Link</p>")
|
assert_equal %(<p>#{link10_result} Link</p>), auto_link("<p>#{link10_raw} Link</p>")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_auto_link_should_sanitize_unsafe_input
|
||||||
|
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
|
||||||
|
assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link(link_raw)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_auto_link_should_sanitize_unsafe_input
|
||||||
|
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
|
||||||
|
assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link(link_raw, :safe => true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_auto_link_should_not_sanitize_safe_input
|
||||||
|
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
|
||||||
|
assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link(link_raw.html_safe)
|
||||||
|
end
|
||||||
|
|
||||||
def test_auto_link_other_protocols
|
def test_auto_link_other_protocols
|
||||||
ftp_raw = 'ftp://example.com/file.txt'
|
ftp_raw = 'ftp://example.com/file.txt'
|
||||||
assert_equal %(Download #{generate_result(ftp_raw)}), auto_link("Download #{ftp_raw}")
|
assert_equal %(Download #{generate_result(ftp_raw)}), auto_link("Download #{ftp_raw}")
|
||||||
|
@ -587,7 +660,12 @@ class TextHelperTest < ActionView::TestCase
|
||||||
assert_equal(%w{Specialized Fuji Giant}, @cycles)
|
assert_equal(%w{Specialized Fuji Giant}, @cycles)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO test textilize_without_paragraph and markdown
|
||||||
if defined? RedCloth
|
if defined? RedCloth
|
||||||
|
def test_textilize_should_be_html_safe
|
||||||
|
assert textilize("*This is Textile!* Rejoice!").html_safe?
|
||||||
|
end
|
||||||
|
|
||||||
def test_textilize
|
def test_textilize
|
||||||
assert_equal("<p><strong>This is Textile!</strong> Rejoice!</p>", textilize("*This is Textile!* Rejoice!"))
|
assert_equal("<p><strong>This is Textile!</strong> Rejoice!</p>", textilize("*This is Textile!* Rejoice!"))
|
||||||
end
|
end
|
||||||
|
@ -600,6 +678,18 @@ class TextHelperTest < ActionView::TestCase
|
||||||
assert_equal("<p>This is worded <strong>strongly</strong></p>", textilize("This is worded <strong>strongly</strong>", :filter_html))
|
assert_equal("<p>This is worded <strong>strongly</strong></p>", textilize("This is worded <strong>strongly</strong>", :filter_html))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_textilize_should_sanitize_unsafe_input
|
||||||
|
assert_equal("<p>This is worded <strong>strongly</strong></p>", textilize("This is worded <strong>strongly</strong><script>code!</script>"))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_textilize_should_not_sanitize_input_if_safe_option
|
||||||
|
assert_equal("<p>This is worded <strong>strongly</strong><script>code!</script></p>", textilize("This is worded <strong>strongly</strong><script>code!</script>", :safe))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_textilize_should_not_sanitize_safe_input
|
||||||
|
assert_equal("<p>This is worded <strong>strongly</strong><script>code!</script></p>", textilize("This is worded <strong>strongly</strong><script>code!</script>".html_safe))
|
||||||
|
end
|
||||||
|
|
||||||
def test_textilize_with_hard_breaks
|
def test_textilize_with_hard_breaks
|
||||||
assert_equal("<p>This is one scary world.<br />\n True.</p>", textilize("This is one scary world.\n True."))
|
assert_equal("<p>This is one scary world.<br />\n True.</p>", textilize("This is one scary world.\n True."))
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue