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
data/profile/vs_erb.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require '../test/helper.rb'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
str_template = <<-EOF
|
5
|
+
<%
|
6
|
+
i = 1
|
7
|
+
%>
|
8
|
+
<table>
|
9
|
+
<tr><th>Name</th><th>Email</th></tr>
|
10
|
+
<% for user in users %>
|
11
|
+
<tr>
|
12
|
+
<td><%=i%>: <%= user.name %></td><td><%= user.email %></td>
|
13
|
+
</tr>
|
14
|
+
<% i += 1 %>
|
15
|
+
<% end %>
|
16
|
+
</table>
|
17
|
+
EOF
|
18
|
+
|
19
|
+
|
20
|
+
class User
|
21
|
+
|
22
|
+
attr_accessor :name
|
23
|
+
attr_accessor :email
|
24
|
+
|
25
|
+
sandboxed_methods :name, :email
|
26
|
+
|
27
|
+
def initialize()
|
28
|
+
@name = 'xxxxx'
|
29
|
+
@email = 'yyyyy'
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
users = []
|
37
|
+
for i in 0...100
|
38
|
+
users << User.new
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
erb_compiled_template = SandboxedErb::Template.new.compile_erb_template(str_template)
|
46
|
+
|
47
|
+
|
48
|
+
sandbox_compiled_template = SandboxedErb::Template.new
|
49
|
+
|
50
|
+
#$DEBUG=true
|
51
|
+
if !sandbox_compiled_template.compile(str_template)
|
52
|
+
puts sandbox_compiled_template.get_error
|
53
|
+
exit
|
54
|
+
end
|
55
|
+
|
56
|
+
#$DEBUG=false
|
57
|
+
|
58
|
+
|
59
|
+
erb_result = eval(erb_compiled_template)
|
60
|
+
|
61
|
+
sb_result = sandbox_compiled_template.run(nil, {:users=>users})
|
62
|
+
|
63
|
+
|
64
|
+
if sb_result.nil?
|
65
|
+
puts sandbox_compiled_template.get_error
|
66
|
+
exit
|
67
|
+
end
|
68
|
+
|
69
|
+
if erb_result != sb_result
|
70
|
+
puts erb_result
|
71
|
+
puts sb_result
|
72
|
+
end
|
73
|
+
|
74
|
+
Benchmark.bmbm do |x|
|
75
|
+
x.report("eval template") { 100.times do eval(erb_compiled_template); end }
|
76
|
+
x.report("sandboxed template") { 100.times do sandbox_compiled_template.run(nil, {:users=>users}); end }
|
77
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require 'liquid'
|
3
|
+
|
4
|
+
|
5
|
+
require '../test/helper.rb'
|
6
|
+
require 'benchmark'
|
7
|
+
|
8
|
+
|
9
|
+
str_template = <<-EOF
|
10
|
+
<table>
|
11
|
+
<tr><th>Name</th><th>Email</th></tr>
|
12
|
+
<% for user in users %>
|
13
|
+
<tr>
|
14
|
+
<td><%= user.name %></td><td><%= user.email %></td>
|
15
|
+
</tr>
|
16
|
+
<% end %>
|
17
|
+
</table>
|
18
|
+
EOF
|
19
|
+
|
20
|
+
ltemplate = <<-EOF
|
21
|
+
<table>
|
22
|
+
<tr><th>Name</th><th>Email</th></tr>
|
23
|
+
{% for user in users %}
|
24
|
+
<tr>
|
25
|
+
<td>{{ user.name }}</td><td>{{ user.email }}</td>
|
26
|
+
</tr>
|
27
|
+
{% endfor %}
|
28
|
+
</table>
|
29
|
+
EOF
|
30
|
+
|
31
|
+
|
32
|
+
class User
|
33
|
+
|
34
|
+
attr_accessor :name
|
35
|
+
attr_accessor :email
|
36
|
+
|
37
|
+
sandboxed_methods :name, :email
|
38
|
+
liquid_methods :name, :email
|
39
|
+
|
40
|
+
def initialize()
|
41
|
+
@name = 'xxxxx'
|
42
|
+
@email = 'yyyyy'
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
users = []
|
50
|
+
for i in 0...100
|
51
|
+
users << User.new
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
erb_compiled_template = SandboxedErb::Template.new.compile_erb_template(str_template)
|
57
|
+
|
58
|
+
liquid_template = Liquid::Template.parse(ltemplate)
|
59
|
+
|
60
|
+
sandbox_compiled_template = SandboxedErb::Template.new
|
61
|
+
|
62
|
+
if !sandbox_compiled_template.compile(str_template)
|
63
|
+
puts sandbox_compiled_template.get_error
|
64
|
+
exit
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
erb_result = eval(erb_compiled_template)
|
70
|
+
|
71
|
+
sb_result = sandbox_compiled_template.run(nil, {:users=>users})
|
72
|
+
|
73
|
+
|
74
|
+
if sb_result.nil?
|
75
|
+
puts sandbox_compiled_template.get_error
|
76
|
+
exit
|
77
|
+
end
|
78
|
+
|
79
|
+
if erb_result != sb_result
|
80
|
+
puts erb_result
|
81
|
+
puts sb_result
|
82
|
+
end
|
83
|
+
|
84
|
+
liquid_result = liquid_template.render({'users'=>users})
|
85
|
+
|
86
|
+
if liquid_result != sb_result
|
87
|
+
puts liquid_result.inspect
|
88
|
+
puts sb_result.inspect
|
89
|
+
end
|
90
|
+
|
91
|
+
Benchmark.bmbm do |x|
|
92
|
+
x.report("eval template") { 100.times do eval(erb_compiled_template); end }
|
93
|
+
x.report("sandboxed template") { 100.times do sandbox_compiled_template.run(nil, {:users=>users}); end }
|
94
|
+
x.report("liquid template") { 100.times do liquid_template.render({'users'=>users}); end }
|
95
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{sandboxed_erb}
|
8
|
+
s.version = "0.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["MarkPent"]
|
12
|
+
s.date = %q{2011-06-05}
|
13
|
+
s.description = %q{All your customers to extend your web application by exposing erb templates that can be safely run on your server within a sandbox.}
|
14
|
+
s.email = %q{mark.pent@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"LICENSE.txt",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"example/controller.rb",
|
27
|
+
"example/example.rb",
|
28
|
+
"example/listing.sbhtml",
|
29
|
+
"example/note.rb",
|
30
|
+
"example/users.rb",
|
31
|
+
"example/view_notes.sbhtml",
|
32
|
+
"lib/sandboxed_erb.rb",
|
33
|
+
"lib/sandboxed_erb/sandbox_methods.rb",
|
34
|
+
"lib/sandboxed_erb/system_mixins.rb",
|
35
|
+
"lib/sandboxed_erb/template.rb",
|
36
|
+
"lib/sandboxed_erb/tree_processor.rb",
|
37
|
+
"profile/vs_erb.rb",
|
38
|
+
"profile/vs_liquid.rb",
|
39
|
+
"sandboxed_erb.gemspec",
|
40
|
+
"test/helper.rb",
|
41
|
+
"test/test_compile_errors.rb",
|
42
|
+
"test/test_error_handling.rb",
|
43
|
+
"test/test_sandboxed_erb.rb",
|
44
|
+
"test/test_valid_templates.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/markpent/SandboxedERB}
|
47
|
+
s.licenses = ["MIT"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.7.2}
|
50
|
+
s.summary = %q{Run an erb template in a sandbox.}
|
51
|
+
|
52
|
+
if s.respond_to? :specification_version then
|
53
|
+
s.specification_version = 3
|
54
|
+
|
55
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
56
|
+
s.add_runtime_dependency(%q<partialruby>, [">= 0.2.0"])
|
57
|
+
s.add_runtime_dependency(%q<ruby_parser>, [">= 2.0.6"])
|
58
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
59
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
60
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.1"])
|
61
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<partialruby>, [">= 0.2.0"])
|
64
|
+
s.add_dependency(%q<ruby_parser>, [">= 2.0.6"])
|
65
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
66
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
67
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.1"])
|
68
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
69
|
+
end
|
70
|
+
else
|
71
|
+
s.add_dependency(%q<partialruby>, [">= 0.2.0"])
|
72
|
+
s.add_dependency(%q<ruby_parser>, [">= 2.0.6"])
|
73
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
74
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
75
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.1"])
|
76
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'sandboxed_erb'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestCompileErrors < Test::Unit::TestCase
|
4
|
+
should "report insecure call during compile: global" do
|
5
|
+
str_template = "i shoudl not be
|
6
|
+
able to get
|
7
|
+
global: <%= $some_global_value %>
|
8
|
+
"
|
9
|
+
template = SandboxedErb::Template.new
|
10
|
+
assert_equal false, template.compile(str_template)
|
11
|
+
|
12
|
+
assert_equal "Line 3: You cannot access global variables in a template", template.get_error
|
13
|
+
end
|
14
|
+
|
15
|
+
should "report insecure call during compile: global asign" do
|
16
|
+
str_template = "i shoudl not be
|
17
|
+
able to get
|
18
|
+
global: <%= $some_global_value = 10 %>
|
19
|
+
"
|
20
|
+
template = SandboxedErb::Template.new
|
21
|
+
assert_equal false, template.compile(str_template)
|
22
|
+
|
23
|
+
assert_equal "Line 3: You cannot assign global variables in a template", template.get_error
|
24
|
+
end
|
25
|
+
|
26
|
+
should "report insecure call during compile: const" do
|
27
|
+
str_template = "i shoudl not be
|
28
|
+
able to get
|
29
|
+
global: <%= SOME_CONST %>
|
30
|
+
"
|
31
|
+
template = SandboxedErb::Template.new
|
32
|
+
assert_equal false, template.compile(str_template)
|
33
|
+
|
34
|
+
assert_equal "Line 3: You cannot access a constant in a template", template.get_error
|
35
|
+
end
|
36
|
+
|
37
|
+
should "report insecure call during compile: const assign" do
|
38
|
+
str_template = "i shoudl not be
|
39
|
+
able to get
|
40
|
+
global: <%= SOME_CONST = 10 %>
|
41
|
+
"
|
42
|
+
template = SandboxedErb::Template.new
|
43
|
+
assert_equal false, template.compile(str_template)
|
44
|
+
|
45
|
+
assert_equal "Line 3: You cannot define a constant in a template", template.get_error
|
46
|
+
end
|
47
|
+
|
48
|
+
should "report insecure call during compile: def" do
|
49
|
+
str_template = "i shoudl not be
|
50
|
+
able to get
|
51
|
+
<%
|
52
|
+
def invalid_func
|
53
|
+
|
54
|
+
end
|
55
|
+
%>
|
56
|
+
"
|
57
|
+
template = SandboxedErb::Template.new
|
58
|
+
assert_equal false, template.compile(str_template)
|
59
|
+
assert_equal "Line 4: You cannot define a method in a template", template.get_error
|
60
|
+
end
|
61
|
+
|
62
|
+
should "report insecure call during compile: module def" do
|
63
|
+
str_template = "i shoudl not be
|
64
|
+
able to get
|
65
|
+
<%
|
66
|
+
module Not
|
67
|
+
def invalid_func
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
%>
|
72
|
+
"
|
73
|
+
template = SandboxedErb::Template.new
|
74
|
+
assert_equal false, template.compile(str_template)
|
75
|
+
|
76
|
+
assert_equal "Line 4: You cannot define a module in a template", template.get_error
|
77
|
+
end
|
78
|
+
|
79
|
+
should "report insecure call during compile: class def" do
|
80
|
+
str_template = "i shoudl not be
|
81
|
+
able to get
|
82
|
+
<%
|
83
|
+
class Not
|
84
|
+
def invalid_func
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
%>
|
89
|
+
"
|
90
|
+
template = SandboxedErb::Template.new
|
91
|
+
assert_equal false, template.compile(str_template)
|
92
|
+
|
93
|
+
assert_equal "Line 4: You cannot define a class in a template", template.get_error
|
94
|
+
end
|
95
|
+
|
96
|
+
should "report insecure call during compile: member vars" do
|
97
|
+
str_template = "i shoudl not be
|
98
|
+
able to get
|
99
|
+
<%= @test %>
|
100
|
+
"
|
101
|
+
template = SandboxedErb::Template.new
|
102
|
+
assert_equal false, template.compile(str_template)
|
103
|
+
|
104
|
+
assert_equal "Line 3: You cannot access instance members in a template", template.get_error
|
105
|
+
end
|
106
|
+
|
107
|
+
should "report insecure call during compile: member var assign" do
|
108
|
+
str_template = "i shoudl not be
|
109
|
+
able to get
|
110
|
+
<% @test = 2 %>
|
111
|
+
"
|
112
|
+
template = SandboxedErb::Template.new
|
113
|
+
assert_equal false, template.compile(str_template)
|
114
|
+
|
115
|
+
assert_equal "Line 3: You cannot assign instance members in a template", template.get_error
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
should "report insecure call during compile: cvar assign" do
|
120
|
+
str_template = "i shoudl not be
|
121
|
+
able to get
|
122
|
+
<% SomeClass.some_attr = 2 %>
|
123
|
+
"
|
124
|
+
template = SandboxedErb::Template.new
|
125
|
+
assert_equal false, template.compile(str_template)
|
126
|
+
assert_equal "Line 3: You cannot access a constant in a template", template.get_error
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
should "report compile errors" do
|
131
|
+
str_template = "i shoudl not be
|
132
|
+
able to get
|
133
|
+
<%
|
134
|
+
for x out of not
|
135
|
+
%>
|
136
|
+
"
|
137
|
+
template = SandboxedErb::Template.new
|
138
|
+
assert_equal false, template.compile(str_template)
|
139
|
+
|
140
|
+
assert_match /compile error\nline:4: syntax error/, template.get_error
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestErrorHandling < Test::Unit::TestCase
|
4
|
+
should "handle missing function of object" do
|
5
|
+
|
6
|
+
class TestClass
|
7
|
+
sandboxed_methods :ok_to_call
|
8
|
+
|
9
|
+
def ok_to_call
|
10
|
+
"A"
|
11
|
+
end
|
12
|
+
|
13
|
+
def not_ok_to_call
|
14
|
+
"B"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
str_template = "not_ok_to_call = <%=tc.not_ok_to_call.some_other_thingo.and_this %>"
|
19
|
+
template = SandboxedErb::Template.new
|
20
|
+
template.compile(str_template)
|
21
|
+
assert_equal nil,template.run(nil, {:tc=>TestClass.new})
|
22
|
+
|
23
|
+
assert_equal "Error on line 1: Unknown method 'not_ok_to_call' on object 'TestErrorHandling::TestClass'", template.get_error
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
should "handle missing functions" do
|
28
|
+
|
29
|
+
|
30
|
+
str_template = "some method = <%=some_method_that_does_not_exist(1) %>"
|
31
|
+
template = SandboxedErb::Template.new
|
32
|
+
template.compile(str_template)
|
33
|
+
assert_equal nil,template.run(nil, {:tc=>TestClass.new})
|
34
|
+
|
35
|
+
assert_equal "Error on line 1: Unknown method: some_method_that_does_not_exist", template.get_error
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
should "report exceptions in mixins" do
|
41
|
+
|
42
|
+
module MixinTest1
|
43
|
+
def test_mixin_method1(val)
|
44
|
+
raise "mixin exception"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
str_template = "mixin =
|
50
|
+
<%= test_mixin_method1('A') %>"
|
51
|
+
template = SandboxedErb::Template.new([MixinTest1])
|
52
|
+
assert_equal true, template.compile(str_template)
|
53
|
+
assert_equal nil, template.run(nil, {})
|
54
|
+
|
55
|
+
assert_equal "Error on line 2: Error calling test_mixin_method1: mixin exception", template.get_error
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|