/
common.rb
93 lines (78 loc) · 1.95 KB
/
common.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# SafeERB
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