Handle more unsafe String methods (#33990)

* Handle more unsafe String methods

* Fix codeclimate issue

* Revert stylistic change

[Janosch Müller + Rafael Mendonça França]
This commit is contained in:
Janosch Müller 2018-09-28 02:50:21 +02:00 committed by Rafael França
parent 6b9cc6fee1
commit 47f2686148
4 changed files with 102 additions and 11 deletions

View File

@ -1,3 +1,8 @@
* Treat `#delete_prefix`, `#delete_suffix` and `#unicode_normalize` results as non-`html_safe`.
Ensure safety of arguments for `#insert`, `#[]=` and `#replace` calls on `html_safe` Strings.
*Janosch Müller*
* Changed `ActiveSupport::TaggedLogging.new` to return a new logger instance instead
of mutating the one received as parameter.

View File

@ -134,8 +134,9 @@ end
module ActiveSupport #:nodoc:
class SafeBuffer < String
UNSAFE_STRING_METHODS = %w(
capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
slice squeeze strip sub succ swapcase tr tr_s upcase
capitalize chomp chop delete delete_prefix delete_suffix
downcase gsub lstrip next reverse rstrip slice squeeze strip
sub succ swapcase tr tr_s unicode_normalize upcase
)
alias_method :original_concat, :concat
@ -186,10 +187,22 @@ module ActiveSupport #:nodoc:
end
alias << concat
def insert(index, value)
super(index, html_escape_interpolated_argument(value))
end
def prepend(value)
super(html_escape_interpolated_argument(value))
end
def replace(value)
super(html_escape_interpolated_argument(value))
end
def []=(index, value)
super(index, html_escape_interpolated_argument(value))
end
def +(other)
dup.concat(other)
end

View File

@ -892,6 +892,54 @@ class OutputSafetyTest < ActiveSupport::TestCase
assert_predicate string, :html_safe?
end
test "Inserting safe into safe yields safe" do
string = "foo".html_safe
string.insert(0, "<b>".html_safe)
assert_equal "<b>foo", string
assert_predicate string, :html_safe?
end
test "Inserting unsafe into safe yields escaped safe" do
string = "foo".html_safe
string.insert(0, "<b>")
assert_equal "&lt;b&gt;foo", string
assert_predicate string, :html_safe?
end
test "Replacing safe with safe yields safe" do
string = "foo".html_safe
string.replace("<b>".html_safe)
assert_equal "<b>", string
assert_predicate string, :html_safe?
end
test "Replacing safe with unsafe yields escaped safe" do
string = "foo".html_safe
string.replace("<b>")
assert_equal "&lt;b&gt;", string
assert_predicate string, :html_safe?
end
test "Replacing index of safe with safe yields safe" do
string = "foo".html_safe
string[0] = "<b>".html_safe
assert_equal "<b>oo", string
assert_predicate string, :html_safe?
end
test "Replacing index of safe with unsafe yields escaped safe" do
string = "foo".html_safe
string[0] = "<b>"
assert_equal "&lt;b&gt;oo", string
assert_predicate string, :html_safe?
end
test "emits normal string yaml" do
assert_equal "foo".to_yaml, "foo".html_safe.to_yaml(foo: 1)
end

View File

@ -75,16 +75,41 @@ class SafeBufferTest < ActiveSupport::TestCase
assert_equal "my_test", str
end
test "Should not return safe buffer from gsub" do
altered_buffer = @buffer.gsub("", "asdf")
assert_equal "asdf", altered_buffer
assert_not_predicate altered_buffer, :html_safe?
end
{
capitalize: nil,
chomp: nil,
chop: nil,
delete: "foo",
delete_prefix: "foo",
delete_suffix: "foo",
downcase: nil,
gsub: ["foo", "bar"],
lstrip: nil,
next: nil,
reverse: nil,
rstrip: nil,
slice: "foo",
squeeze: nil,
strip: nil,
sub: ["foo", "bar"],
succ: nil,
swapcase: nil,
tr: ["foo", "bar"],
tr_s: ["foo", "bar"],
unicode_normalize: nil,
upcase: nil,
}.each do |unsafe_method, dummy_args|
test "Should not return safe buffer from #{unsafe_method}" do
skip unless String.method_defined?(unsafe_method)
altered_buffer = @buffer.send(unsafe_method, *dummy_args)
assert_not_predicate altered_buffer, :html_safe?
end
test "Should not return safe buffer from gsub!" do
@buffer.gsub!("", "asdf")
assert_equal "asdf", @buffer
assert_not_predicate @buffer, :html_safe?
test "Should not return safe buffer from #{unsafe_method}!" do
skip unless String.method_defined?("#{unsafe_method}!")
@buffer.send("#{unsafe_method}!", *dummy_args)
assert_not_predicate @buffer, :html_safe?
end
end
test "Should escape dirty buffers on add" do