From 80b6ac3bc74999c3cef071cf277d8ee0384126a8 Mon Sep 17 00:00:00 2001 From: Dylan Thacker-Smith Date: Sat, 4 Jul 2015 23:59:23 -0400 Subject: [PATCH] Add taint warnings to the context rather than the template. --- lib/liquid/context.rb | 4 ++++ lib/liquid/variable.rb | 16 ++++++++++------ test/integration/drop_test.rb | 6 ++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb index bb52558e..042a5432 100644 --- a/lib/liquid/context.rb +++ b/lib/liquid/context.rb @@ -33,6 +33,10 @@ module Liquid @filters = [] end + def warnings + @warnings ||= [] + end + def strainer @strainer ||= Strainer.create(self, @filters) end diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb index 0930b0b0..ba860b09 100644 --- a/lib/liquid/variable.rb +++ b/lib/liquid/variable.rb @@ -74,7 +74,7 @@ module Liquid @filters.inject(context.evaluate(@name)) do |output, (filter_name, filter_args, filter_kwargs)| filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs) context.invoke(filter_name, output, *filter_args) - end.tap{ |obj| taint_check(obj) } + end.tap{ |obj| taint_check(context, obj) } end private @@ -106,16 +106,20 @@ module Liquid parsed_args end - def taint_check(obj) - if obj.tainted? + def taint_check(context, obj) + if obj.tainted? && Template.taint_mode != :lax @markup =~ QuotedFragment name = Regexp.last_match(0) + + error = TaintedError.new("variable '#{name}' is tainted and was not escaped") + error.line_number = line_number + error.template_name = context.template_name + case Template.taint_mode when :warn - @warnings ||= [] - @warnings << "variable '#{name}' is tainted and was not escaped" + context.warnings << error when :error - raise TaintedError, "Error - variable '#{name}' is tainted and was not escaped" + raise error end end end diff --git a/test/integration/drop_test.rb b/test/integration/drop_test.rb index d2ee2d78..e3dd5095 100644 --- a/test/integration/drop_test.rb +++ b/test/integration/drop_test.rb @@ -124,8 +124,10 @@ class DropsTest < Minitest::Test def test_rendering_warns_on_tainted_attr with_taint_mode(:warn) do tpl = Liquid::Template.parse('{{ product.user_input }}') - tpl.render!('product' => ProductDrop.new) - assert_match /tainted/, tpl.warnings.first + context = Context.new('product' => ProductDrop.new) + tpl.render!(context) + assert_equal [Liquid::TaintedError], context.warnings.map(&:class) + assert_equal "variable 'product.user_input' is tainted and was not escaped", context.warnings.first.to_s(false) end end