Skip to content
Browse files

replacing safe_erb... wtf did it go?

  • Loading branch information...
1 parent 48830e7 commit ea34f7bc2f4d5256173e3080e3928d3cf1a6c1b0 Aaron Bedra committed Apr 25, 2009
Showing with 113 additions and 0 deletions.
  1. +113 −0 lib/safe_erb.rb
View
113 lib/safe_erb.rb
@@ -0,0 +1,113 @@
+require 'erb'
+require 'action_controller'
+require 'action_view'
+
+class ActionController::Base
+ # Object#taint is set when the request comes from FastCGI or WEBrick,
+ # but it is not set in Mongrel and also functional / integration testing
+ # so we'll set it anyways in the filter
+ before_filter :taint_request
+
+ def render_with_checking_tainted(*args, &blk)
+ if @skip_checking_tainted
+ render_without_checking_tainted(*args, &blk)
+ else
+ ERB.with_checking_tainted do
+ render_without_checking_tainted(*args, &blk)
+ end
+ end
+ end
+
+ alias_method_chain :render, :checking_tainted
+
+ private
+
+ def taint_hash(hash)
+ hash.each do |k, v|
+ case v
+ when String
+ v.taint
+ when Hash
+ taint_hash(v)
+ end
+ end
+ end
+
+ def taint_request
+ taint_hash(params)
+ cookies.each do |k, v|
+ v.taint
+ end
+ end
+end
+
+class String
+ def concat_unless_tainted(str)
+ raise "attempted to output tainted string: #{str}" if str.is_a?(String) && str.tainted?
+ concat(str)
+ end
+end
+
+class ERB
+ cattr_accessor :check_tainted
+ alias_method :original_set_eoutvar, :set_eoutvar
+
+ def self.with_checking_tainted(&block)
+ # not thread safe
+ ERB.check_tainted = true
+ begin
+ yield
+ ensure
+ ERB.check_tainted = false
+ end
+ end
+
+ def set_eoutvar(compiler, eoutvar = '_erbout')
+ original_set_eoutvar(compiler, eoutvar)
+ if check_tainted
+ if compiler.respond_to?(:insert_cmd)
+ compiler.insert_cmd = "#{eoutvar}.concat_unless_tainted"
+ else
+ compiler.put_cmd = "#{eoutvar}.concat_unless_tainted"
+ end
+ end
+ end
+
+ module Util
+ alias_method :html_escape_without_untaint, :html_escape
+
+ def html_escape(s)
+ h = html_escape_without_untaint(s)
+ h.untaint
+ h
+ end
+
+ alias_method :h, :html_escape
+
+ module_function :h
+ module_function :html_escape
+ module_function :html_escape_without_untaint
+ end
+end
+
+module ActionView::Helpers::SanitizeHelper
+ def strip_tags_with_untaint(html)
+ str = strip_tags_without_untaint(html)
+ str.untaint
+ str
+ end
+
+ alias_method_chain :strip_tags, :untaint
+end
+
+module ActionView
+ module Helpers
+ module TagHelper
+ def escape_once_with_untaint(html)
+ escape_once_without_untaint(html).untaint
+ end
+
+ alias_method_chain :escape_once, :untaint
+ end
+ end
+end

0 comments on commit ea34f7b

Please sign in to comment.
Something went wrong with that request. Please try again.