sandboxed_erb 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +127 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/example/controller.rb +11 -0
- data/example/example.rb +87 -0
- data/example/listing.sbhtml +26 -0
- data/example/note.rb +17 -0
- data/example/users.rb +55 -0
- data/example/view_notes.sbhtml +9 -0
- data/lib/sandboxed_erb.rb +45 -0
- data/lib/sandboxed_erb/sandbox_methods.rb +93 -0
- data/lib/sandboxed_erb/system_mixins.rb +37 -0
- data/lib/sandboxed_erb/template.rb +224 -0
- data/lib/sandboxed_erb/tree_processor.rb +215 -0
- data/profile/vs_erb.rb +77 -0
- data/profile/vs_liquid.rb +95 -0
- data/sandboxed_erb.gemspec +79 -0
- data/test/helper.rb +18 -0
- data/test/test_compile_errors.rb +142 -0
- data/test/test_error_handling.rb +59 -0
- data/test/test_sandboxed_erb.rb +230 -0
- data/test/test_valid_templates.rb +170 -0
- metadata +181 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the sandboxed_erb project, https://github.com/markpent/SandboxedERB
|
4
|
+
|
5
|
+
Copyright (c) 2011 Mark Pentland <mark.pent@gmail.com>
|
6
|
+
|
7
|
+
sandboxed_erb is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
sandboxed_erb is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with shikashi. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
|
22
|
+
|
23
|
+
require "erb"
|
24
|
+
require "partialruby"
|
25
|
+
require "sandboxed_erb/template"
|
26
|
+
require "sandboxed_erb/tree_processor"
|
27
|
+
require "sandboxed_erb/sandbox_methods"
|
28
|
+
require "sandboxed_erb/system_mixins"
|
29
|
+
|
30
|
+
|
31
|
+
module SandboxedErb
|
32
|
+
class Error < ::StandardError #:nodoc: all
|
33
|
+
end
|
34
|
+
|
35
|
+
class CompileError < Error #:nodoc: all
|
36
|
+
end
|
37
|
+
class CompileSecurityError < Error #:nodoc: all
|
38
|
+
end
|
39
|
+
class RuntimeError < Error #:nodoc: all
|
40
|
+
end
|
41
|
+
class RuntimeSecurityError < Error #:nodoc: all
|
42
|
+
end
|
43
|
+
class MissingMethodError < Error #:nodoc: all
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the sandboxed_erb project, https://github.com/markpent/SandboxedERB
|
4
|
+
|
5
|
+
Copyright (c) 2011 Mark Pentland <mark.pent@gmail.com>
|
6
|
+
|
7
|
+
sandboxed_erb is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
sandboxed_erb is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with shikashi. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
|
22
|
+
#Adds the sandboxed_methods and not_sandboxed_methods to Module class so it is avialble to all classes.
|
23
|
+
class Module
|
24
|
+
|
25
|
+
#Specify what methods you want to be accessable from the sandbox.
|
26
|
+
#
|
27
|
+
#Example
|
28
|
+
# class SomeClass
|
29
|
+
# sandboxed_methods :some_method
|
30
|
+
# def some_method
|
31
|
+
# "this is ok to call"
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
#If the object has a method called set_sandbox_context, it will be passed the sandbox_context, which is a map containing the context passed to SandboxedErb::Template.run, as well as another entry keys to :locals which contains the locals map passed to run.
|
36
|
+
def sandboxed_methods(*allowed_methods)
|
37
|
+
_sb_allowed_methods_map = {}
|
38
|
+
allowed_methods.each { |meth|
|
39
|
+
_sb_allowed_methods_map[meth.to_s.intern] = true
|
40
|
+
}
|
41
|
+
|
42
|
+
define_method :_sbm do |meth, sandbox_context, *args|
|
43
|
+
if _sb_allowed_methods_map[meth]
|
44
|
+
self.set_sandbox_context(sandbox_context) if self.respond_to?(:set_sandbox_context)
|
45
|
+
begin
|
46
|
+
self.__send__(meth, *args)
|
47
|
+
rescue Exception=>e
|
48
|
+
raise "Error calling #{meth}: #{e.message}"
|
49
|
+
end
|
50
|
+
else
|
51
|
+
puts _sb_allowed_methods_map.inspect if $DEBUG
|
52
|
+
raise SandboxedErb::MissingMethodError, "Unknown method '#{meth}' on object '#{self.class.name}'"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
#Shortcut to allow everything except a few methods
|
59
|
+
#
|
60
|
+
#This will not include any superclass methods unless include_superclasses = true
|
61
|
+
#
|
62
|
+
#Example
|
63
|
+
# class SomeClass
|
64
|
+
# not_sandboxed_methods :unsafe_method
|
65
|
+
# def some_method
|
66
|
+
# "this is ok to call"
|
67
|
+
# end
|
68
|
+
# def unsafe_method
|
69
|
+
# "this is NOT ok to call"
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
def not_sandboxed_methods(include_superclasses = false, *disallowed_methods)
|
73
|
+
|
74
|
+
__the_methods_to_check = public_instance_methods(false)
|
75
|
+
if include_superclasses
|
76
|
+
clz = self.superclass
|
77
|
+
while !clz.nil?
|
78
|
+
unless clz == Object
|
79
|
+
__the_methods_to_check += clz.public_instance_methods(false)
|
80
|
+
end
|
81
|
+
clz = clz.superclass
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
__the_methods_to_check.uniq!
|
87
|
+
|
88
|
+
sandboxed_methods(*__the_methods_to_check)
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the sandboxed_erb project, https://github.com/markpent/SandboxedERB
|
4
|
+
|
5
|
+
Copyright (c) 2011 Mark Pentland <mark.pent@gmail.com>
|
6
|
+
|
7
|
+
sandboxed_erb is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
sandboxed_erb is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with shikashi. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
|
22
|
+
|
23
|
+
#add sandboxed method to basic inbuilt objects
|
24
|
+
|
25
|
+
String.not_sandboxed_methods true
|
26
|
+
Fixnum.not_sandboxed_methods true
|
27
|
+
Float.not_sandboxed_methods true
|
28
|
+
Range.not_sandboxed_methods true
|
29
|
+
Symbol.not_sandboxed_methods true
|
30
|
+
Time.not_sandboxed_methods true
|
31
|
+
Date.not_sandboxed_methods true
|
32
|
+
DateTime.not_sandboxed_methods true
|
33
|
+
NilClass.not_sandboxed_methods true
|
34
|
+
Array.not_sandboxed_methods true
|
35
|
+
Hash.not_sandboxed_methods true
|
36
|
+
FalseClass.not_sandboxed_methods true
|
37
|
+
TrueClass.not_sandboxed_methods true
|
@@ -0,0 +1,224 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the sandboxed_erb project, https://github.com/markpent/SandboxedERB
|
4
|
+
|
5
|
+
Copyright (c) 2011 Mark Pentland <mark.pent@gmail.com>
|
6
|
+
|
7
|
+
sandboxed_erb is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
sandboxed_erb is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with shikashi. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
|
22
|
+
require "erb"
|
23
|
+
require "partialruby"
|
24
|
+
|
25
|
+
module SandboxedErb
|
26
|
+
|
27
|
+
#This class represents a template which can be compiled then run multiple times.
|
28
|
+
#
|
29
|
+
#When declaring a template, pass an array of Mixin classes to the contructor to allow the template access to the Mixin methods.
|
30
|
+
#
|
31
|
+
#Example
|
32
|
+
# module ExampleHelper
|
33
|
+
# def format_date(date, format)
|
34
|
+
# if format == :short_date
|
35
|
+
# date.strftime("%d %b %Y %H:%M")
|
36
|
+
# else
|
37
|
+
# "unknown format: #{format}"
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# def current_time
|
42
|
+
# DateTime.now
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# template = SandboxedErb::Template.new([ExampleHelper])
|
47
|
+
# #the template will now have access to the format_date() and current_time() helper function
|
48
|
+
# template.compile('the date = <%=format_date(current_time, :short_date)%>')
|
49
|
+
|
50
|
+
class Template
|
51
|
+
|
52
|
+
#minins is an array of helper classes which expose methods to the template
|
53
|
+
def initialize(mixins = [])
|
54
|
+
@mixins = mixins.collect { |clz| "include #{clz.name}"}.join("\n")
|
55
|
+
end
|
56
|
+
|
57
|
+
#compile the template
|
58
|
+
#
|
59
|
+
#if the template does not compile, false is returned and get_error should be called to get the compile error.
|
60
|
+
def compile(str_template)
|
61
|
+
|
62
|
+
erb_template = compile_erb_template(str_template)
|
63
|
+
return false if erb_template.nil?
|
64
|
+
#we now have a normal compile erb template (which is just ruby code)
|
65
|
+
|
66
|
+
sandboxed_compiled_template = sandbox_code(erb_template)
|
67
|
+
puts sandboxed_compiled_template if $DEBUG
|
68
|
+
return false if sandboxed_compiled_template.nil?
|
69
|
+
|
70
|
+
@clazz_name = "SandboxedErb::TClass#{self.object_id}"
|
71
|
+
@file_name = "tclass_#{self.object_id}"
|
72
|
+
|
73
|
+
clazz_str = <<-EOF
|
74
|
+
class #{@clazz_name} < SandboxedErb::TemplateBase
|
75
|
+
#{@mixins}
|
76
|
+
def run_internal()
|
77
|
+
#{sandboxed_compiled_template}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
#{@clazz_name}.new
|
81
|
+
EOF
|
82
|
+
|
83
|
+
begin
|
84
|
+
@template_runner = eval(clazz_str, nil, @file_name)
|
85
|
+
rescue Exception=>e
|
86
|
+
@error = "Invalid code generated: #{e.message}"
|
87
|
+
return false
|
88
|
+
end
|
89
|
+
|
90
|
+
true
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
#run a compiled template
|
95
|
+
#* context: A map of context objects that will be available to helper functions and instance variables, and available to sandboxed objects through the set_sandbox_context callback.
|
96
|
+
#* locals: A map of local objects that will be available to the template, and available to sandboxed objects through the set_sandbox_context callback as the :locals entry.
|
97
|
+
#If the template runs successfully, the geneated content is returned. If an error occures, nil is returned and get_error should be called to get the error information.
|
98
|
+
def run(context, locals)
|
99
|
+
begin
|
100
|
+
@template_runner.run(context, locals)
|
101
|
+
rescue Exception=>e
|
102
|
+
@error = e.message
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def compile_erb_template(str_template) #:nodoc:
|
108
|
+
ecompiler = ERB::Compiler.new(nil)
|
109
|
+
|
110
|
+
ecompiler.put_cmd = "_erbout.concat"
|
111
|
+
ecompiler.insert_cmd = "_erbout.concat"
|
112
|
+
|
113
|
+
cmd = []
|
114
|
+
cmd.push "_erbout = ''"
|
115
|
+
|
116
|
+
ecompiler.pre_cmd = cmd
|
117
|
+
|
118
|
+
cmd = []
|
119
|
+
cmd.push('_erbout')
|
120
|
+
|
121
|
+
ecompiler.post_cmd = cmd
|
122
|
+
ecompiler.compile(str_template)
|
123
|
+
end
|
124
|
+
|
125
|
+
def sandbox_code(erb_template) #:nodoc:
|
126
|
+
@error = nil
|
127
|
+
tree = nil
|
128
|
+
begin
|
129
|
+
tree = RubyParser.new.parse erb_template
|
130
|
+
rescue Exception=>e
|
131
|
+
#the message is pretty useless.. lets eval the code (it wont get executed because of the compile error)
|
132
|
+
begin
|
133
|
+
#extra bit of caution.. run in $SAFE=4
|
134
|
+
t = Thread.new {
|
135
|
+
$SAFE = 4
|
136
|
+
eval(erb_template, nil, "line")
|
137
|
+
}
|
138
|
+
t.join
|
139
|
+
rescue Exception=>e2
|
140
|
+
@error = e2.message
|
141
|
+
return nil
|
142
|
+
end
|
143
|
+
#if we got here then somehow code that would not compile using RubyParser eval'ed ok...
|
144
|
+
throw "SYSTEM ERROR: you may be owned! Code that should not be able to compile has run!"
|
145
|
+
end
|
146
|
+
begin
|
147
|
+
context = PartialRuby::PureRubyContext.new
|
148
|
+
tree_processor = SandboxedErb::TreeProcessor.new()
|
149
|
+
|
150
|
+
tree = tree_processor.process(tree)
|
151
|
+
emulationcode = context.emul tree
|
152
|
+
rescue Exception=>e
|
153
|
+
@error = e.message
|
154
|
+
return nil
|
155
|
+
end
|
156
|
+
emulationcode
|
157
|
+
end
|
158
|
+
|
159
|
+
def get_error
|
160
|
+
@error
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class TemplateBase #:nodoc: all
|
165
|
+
def initialize
|
166
|
+
@_allowed_methods = {}
|
167
|
+
self.class.included_modules.each { |mod|
|
168
|
+
unless mod == Kernel
|
169
|
+
mod.public_instance_methods.each { |m|
|
170
|
+
@_allowed_methods[m.intern] = true
|
171
|
+
}
|
172
|
+
end
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
def run(context, locals)
|
177
|
+
context = {} if context.nil?
|
178
|
+
context[:locals] = locals
|
179
|
+
unless context.nil?
|
180
|
+
for k in context.keys
|
181
|
+
eval("@#{k} = context[k]")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
@_sb_context = context
|
185
|
+
@_locals = locals
|
186
|
+
@_line = 1
|
187
|
+
begin
|
188
|
+
run_internal
|
189
|
+
rescue Exception=>e
|
190
|
+
raise "Error on line #{@_line}: #{e.message}"
|
191
|
+
ensure
|
192
|
+
#cleanup the context
|
193
|
+
unless context.nil?
|
194
|
+
for k in context.keys
|
195
|
+
eval("@#{k} = nil")
|
196
|
+
end
|
197
|
+
end
|
198
|
+
@_sb_context = nil
|
199
|
+
@_locals = nil
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def _get_local(*args)
|
204
|
+
target = args.shift
|
205
|
+
#check if the target is in the context
|
206
|
+
if @_locals[target]
|
207
|
+
@_locals[target]
|
208
|
+
elsif @_allowed_methods[target] #check if the target is defined in one of the mixin helper functions
|
209
|
+
begin
|
210
|
+
self.send(target, *args)
|
211
|
+
rescue Exception=>e
|
212
|
+
raise "Error calling #{target}: #{e.message}"
|
213
|
+
end
|
214
|
+
else
|
215
|
+
raise "Unknown method: #{target}"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def _sln(line_no)
|
220
|
+
@_line = line_no
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the sandboxed_erb project, https://github.com/markpent/SandboxedERB
|
4
|
+
|
5
|
+
Copyright (c) 2011 Mark Pentland <mark.pent@gmail.com>
|
6
|
+
|
7
|
+
sandboxed_erb is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
sandboxed_erb is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with shikashi. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
|
22
|
+
require "ruby_parser"
|
23
|
+
require "partialruby"
|
24
|
+
require "sexp_processor"
|
25
|
+
|
26
|
+
module SandboxedErb
|
27
|
+
class TreeProcessor < SexpProcessor #:nodoc: all
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
super()
|
31
|
+
self.default_method = :fallback_process
|
32
|
+
self.require_empty = false
|
33
|
+
self.warn_on_default = false
|
34
|
+
|
35
|
+
@hook_handler_name = "@_hook_handler".intern
|
36
|
+
@last_line_number = 0
|
37
|
+
end
|
38
|
+
|
39
|
+
#we treat this same as a call
|
40
|
+
def process_attrasgn(tree)
|
41
|
+
process_call(tree)
|
42
|
+
end
|
43
|
+
|
44
|
+
def process_call(tree)
|
45
|
+
puts tree.inspect if $DEBUG
|
46
|
+
if [:_sbm].include?(tree[2])
|
47
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: #{tree[2].to_s} is a reserved method"
|
48
|
+
elsif tree[1] && tree[1][0] == :lvar && tree[1][1] == :_erbout && tree[2] == :concat #optimisation:call concat on _erbout is safe... dont need to route through _sbm
|
49
|
+
add_line_number(tree, s(tree[0], tree[1], tree[2], process(tree[3])))
|
50
|
+
elsif tree[1] && tree[2] == :to_s && tree[3][0] == :arglist && tree[3].length == 1 #optimisation:call to_s on an object is safe... dont need to route through _sbm
|
51
|
+
add_line_number(tree, s(tree[0], process(tree[1]), tree[2], tree[3]))
|
52
|
+
elsif tree[1]
|
53
|
+
#rewrite obj.call(arg1, arg2, argN) to obj._invoke_sbm(:call, arg1, arg2, argN)
|
54
|
+
args = [:arglist]
|
55
|
+
args << s(:lit, tree[2])
|
56
|
+
args << s(:ivar, "@_sb_context".intern)
|
57
|
+
for i in 1...tree[3].length
|
58
|
+
args << process(tree[3][i])
|
59
|
+
end
|
60
|
+
add_line_number(tree, s(:call, process(tree[1]), :_sbm, args))
|
61
|
+
else
|
62
|
+
#call on mixed in method or passed in variable
|
63
|
+
receiver = s(:self)
|
64
|
+
#rewrite local_call(arg1, arg2, argN) to self._get_local(:local_call, arg1, arg2, argN)
|
65
|
+
args = [:arglist]
|
66
|
+
args << s(:lit, tree[2])
|
67
|
+
for i in 1...tree[3].length
|
68
|
+
args << tree[3][i]
|
69
|
+
end
|
70
|
+
add_line_number(tree, s(:call, s(:self), :_get_local, process(args)))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
#disallowed
|
75
|
+
|
76
|
+
def process_iasgn(tree)
|
77
|
+
puts tree.inspect if $DEBUG
|
78
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot assign instance members in a template"
|
79
|
+
end
|
80
|
+
|
81
|
+
def process_ivar(tree)
|
82
|
+
puts tree.inspect if $DEBUG
|
83
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot access instance members in a template"
|
84
|
+
end
|
85
|
+
|
86
|
+
def process_cvasgn(tree)
|
87
|
+
puts tree.inspect if $DEBUG
|
88
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot assign class members in a template"
|
89
|
+
end
|
90
|
+
|
91
|
+
def process_cvdecl(tree)
|
92
|
+
puts tree.inspect if $DEBUG
|
93
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot declare class members in a template"
|
94
|
+
end
|
95
|
+
|
96
|
+
def process_cdecl(tree)
|
97
|
+
puts tree.inspect if $DEBUG
|
98
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot define a constant in a template"
|
99
|
+
end
|
100
|
+
|
101
|
+
def process_const(tree)
|
102
|
+
puts tree.inspect if $DEBUG
|
103
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot access a constant in a template"
|
104
|
+
end
|
105
|
+
|
106
|
+
def process_class(tree)
|
107
|
+
puts tree.inspect if $DEBUG
|
108
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot define a class in a template"
|
109
|
+
end
|
110
|
+
|
111
|
+
def process_module(tree)
|
112
|
+
puts tree.inspect if $DEBUG
|
113
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot define a module in a template"
|
114
|
+
end
|
115
|
+
|
116
|
+
def process_defn(tree)
|
117
|
+
puts tree.inspect if $DEBUG
|
118
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot define a method in a template"
|
119
|
+
end
|
120
|
+
|
121
|
+
def process_defs(tree)
|
122
|
+
puts tree.inspect if $DEBUG
|
123
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot define a method in a template"
|
124
|
+
end
|
125
|
+
|
126
|
+
def process_super(tree)
|
127
|
+
puts tree.inspect if $DEBUG
|
128
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot call super in a template"
|
129
|
+
end
|
130
|
+
|
131
|
+
def process_gvar(tree)
|
132
|
+
puts tree.inspect if $DEBUG
|
133
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot access global variables in a template"
|
134
|
+
end
|
135
|
+
|
136
|
+
def process_gasgn(tree)
|
137
|
+
puts tree.inspect if $DEBUG
|
138
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot assign global variables in a template"
|
139
|
+
end
|
140
|
+
|
141
|
+
def process_xstr(tree)
|
142
|
+
puts tree.inspect if $DEBUG
|
143
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: You cannot make a system call in a template"
|
144
|
+
end
|
145
|
+
|
146
|
+
def fallback_process(tree)
|
147
|
+
puts tree.inspect if $DEBUG
|
148
|
+
puts "Fallback called" if $DEBUG
|
149
|
+
raise SandboxedErb::CompileSecurityError, "Line #{tree.line}: Invalid call used: #{tree[0]}"
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
#allowed
|
154
|
+
|
155
|
+
[[:block, true],[:lasgn, true],[:arglist, true],[:str, true],[:dstr, true],[:evstr, true],[:lit, true],[:lvar, true],[:for, true], [:while, true], [:do, true], [:if, true], [:case, true], [:when, true], [:array, true], [:hash, true]].each { |action, add_line_number|
|
156
|
+
if add_line_number
|
157
|
+
define_method "process_#{action}".intern do |tree|
|
158
|
+
puts tree.inspect if $DEBUG
|
159
|
+
add_line_number(tree, passthrough(tree))
|
160
|
+
end
|
161
|
+
else
|
162
|
+
define_method "process_#{action}".intern do |tree|
|
163
|
+
puts tree.inspect if $DEBUG
|
164
|
+
passthrough tree
|
165
|
+
end
|
166
|
+
end
|
167
|
+
}
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
private
|
172
|
+
#taken from SexpProcessor: just process the tag by processing all nested tags, leaving current tag untouched...
|
173
|
+
def passthrough(exp)
|
174
|
+
result = self.expected.new
|
175
|
+
type = exp.first
|
176
|
+
exp_orig = nil
|
177
|
+
|
178
|
+
in_context type do
|
179
|
+
until exp.empty? do
|
180
|
+
sub_exp = exp.shift
|
181
|
+
sub_result = nil
|
182
|
+
if Array === sub_exp then
|
183
|
+
sub_result = error_handler(type, exp_orig) do
|
184
|
+
process(sub_exp)
|
185
|
+
end
|
186
|
+
raise "Result is a bad type" unless Array === sub_exp
|
187
|
+
raise "Result does not have a type in front: #{sub_exp.inspect}" unless Symbol === sub_exp.first unless sub_exp.empty?
|
188
|
+
else
|
189
|
+
sub_result = sub_exp
|
190
|
+
end
|
191
|
+
result << sub_result
|
192
|
+
end
|
193
|
+
|
194
|
+
begin
|
195
|
+
result.sexp_type = exp.sexp_type
|
196
|
+
rescue Exception
|
197
|
+
# nothing to do, on purpose
|
198
|
+
end
|
199
|
+
end
|
200
|
+
result
|
201
|
+
end
|
202
|
+
|
203
|
+
def add_line_number(original_tree, processed_tree)
|
204
|
+
if original_tree.respond_to?(:line) && @last_line_number != original_tree.line && !original_tree.line.nil?
|
205
|
+
puts "@last_line_number (#{@last_line_number}) != original_tree.line (#{original_tree.line})" if $DEBUG
|
206
|
+
@last_line_number = original_tree.line
|
207
|
+
s(:block, s(:call, nil, :_sln, s(:arglist, s(:lit, original_tree.line))), processed_tree)
|
208
|
+
else
|
209
|
+
processed_tree
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|