roda 2.12.0 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cfcafebba5d38f3d4346b485721c5625aa0df988
4
- data.tar.gz: c3e1918167a29a21c0a0936cf5296778dba0f052
3
+ metadata.gz: 2f3983563024d2c3f03d3a9edcf291f9a6f128ee
4
+ data.tar.gz: 4ac86dfd93b62b8e4f79f19788cf9dbd110df8f2
5
5
  SHA512:
6
- metadata.gz: a9c3d4d68c0f1e45f1c16edc923eced0070f4e1be5f9fa27465e0e8f398e1b49b0ee8e4dc5daade672f01530487846217b59b7e157f2e3c1f4c7a4fc4955072d
7
- data.tar.gz: ee4d4ea602738536680bc27eec01502105dcb7e6bbccd7aa22cfc305eadf701b0980b2ee43bc37fe3a645434595091c408d99cb1e747675980fc5c5d83dc834f
6
+ metadata.gz: 807d5d4fcc03d18823d045b18cb8cf6ce532ea8501254c2f0ce7f245742e4ea6495e399c0e33ae1f7939726b0cb511bc7cc0d9620ec5d19099df86523d9c9847
7
+ data.tar.gz: cc40d28a3152b29755e7949304a4b3bd3a83147ce3975fe0fba829c332641651134727157726425da90feec610f8acfa6b1efd6ba5e8362c14ba97fb2dfe93a9
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ = 2.13.0 (2016-04-14)
2
+
3
+ * Add :check_paths and :allowed_paths to render plugin options to avoid security issues with template rendering (jeremyevans)
4
+
1
5
  = 2.12.0 (2016-03-15)
2
6
 
3
7
  * Allow error handler access to the request's remaining_path (jeremyevans)
@@ -1,6 +1,7 @@
1
1
  = Roda
2
2
 
3
- Roda is a routing tree web framework toolkit.
3
+ Roda is a routing tree web toolkit, designed for building fast and
4
+ maintainable web applications in ruby.
4
5
 
5
6
  = Installation
6
7
 
@@ -29,9 +30,8 @@ code.
29
30
 
30
31
  === Reliability
31
32
 
32
- Roda is one of the first ruby web frameworks where immutability
33
- is supported and encouraged. Roda apps are designed to be frozen
34
- in production, which eliminates possible thread safety issues.
33
+ Roda supports and encourages immutability. Roda apps are designed
34
+ to be frozen in production, which eliminates possible thread safety issues.
35
35
  Additionally, Roda limits the instance variables, constants, and
36
36
  methods that it uses, so that they do not conflict with the ones
37
37
  you use for your application.
@@ -45,8 +45,8 @@ to get the default behavior.
45
45
  === Performance
46
46
 
47
47
  Roda has low per-request overhead, and the use of a routing tree
48
- and intelligent caching of internal datastructures makes it one
49
- of the fastest ruby web frameworks.
48
+ and intelligent caching of internal datastructures makes it
49
+ significantly faster than popular ruby web frameworks.
50
50
 
51
51
  == Usage
52
52
 
@@ -143,7 +143,7 @@ The +.app+ is an optimization, which saves a few method calls for every request.
143
143
 
144
144
  == The Routing Tree
145
145
 
146
- Roda is called a routing tree web framework because the way most sites are structured,
146
+ Roda is called a routing tree web toolkit because the way most sites are structured,
147
147
  routing takes the form of a tree (based on the URL structure of the site).
148
148
  In general:
149
149
 
@@ -211,8 +211,7 @@ you can easily handle this in the routing tree:
211
211
  end
212
212
 
213
213
  Being able to operate on the request at any point during the routing
214
- is one of the major advantages of Roda, as compared to frameworks
215
- that do not use a routing tree.
214
+ is one of the major advantages of Roda.
216
215
 
217
216
  == Matchers
218
217
 
@@ -784,10 +783,10 @@ Example:
784
783
 
785
784
  === Rendering Templates Derived From User Input
786
785
 
787
- Roda's rendering plugin assumes that template paths given to it are trusted. If you provide a path
788
- to the +render+/+view+ methods that is derived from user input, you are opening yourself
789
- for people rendering arbitrary files on the system that that have a file name ending in the
790
- default template extension. For example, if you do:
786
+ Roda's rendering plugin assumes that template paths given to it are trusted by default.
787
+ If you provide a path to the +render+/+view+ methods that is derived from user input, you
788
+ are opening yourself for people rendering arbitrary files on the system that that have a
789
+ file name ending in the default template extension. For example, if you do:
791
790
 
792
791
  class App < Roda
793
792
  plugin :render
@@ -801,18 +800,14 @@ to render the <tt>/tmp/upload.erb</tt> file. If you have another part of your s
801
800
  allows users to create files with arbitrary extensions (even temporary files), then it may
802
801
  be possible to combine these two issues into a remote code execution exploit.
803
802
 
804
- If you do want to allow users to choose which template to use, you should use a whitelist:
805
-
806
- class App < Roda
807
- plugin :render
808
- ALLOWED_PAGES = %w'page1 page2 page3'
809
- route do |r|
810
- page = r['page']
811
- if ALLOWED_PAGES.include?(page)
812
- view(page)
813
- end
814
- end
815
- end
803
+ To mitigate against this issue, you can use the <tt>:check_paths => true</tt> render
804
+ option, which will check that the full path of the template to be rendered begins with the
805
+ +:views+ directory, and raises an exception if not. You can also use the +:allowed_paths+
806
+ render option to specify which paths are allowed. While
807
+ <tt>:check_paths => true</tt> is not currently the default, it will become the default in
808
+ Roda 3. Note that when specifying the +:path+ option when rendering a template, Roda will
809
+ not check paths, as it assumes that users and libraries that use this option will be checking
810
+ such paths manually.
816
811
 
817
812
  == Reloading
818
813
 
@@ -828,9 +823,6 @@ Most rack-based reloaders will work with Roda, including:
828
823
 
829
824
  By design, Roda has a very small core, providing only the essentials.
830
825
  All nonessential features are added via plugins.
831
- This is why Roda is referred to as a routing tree web framework toolkit.
832
- Using a combination of Roda plugins,
833
- you can build the routing tree web framework that suits your needs.
834
826
 
835
827
  Roda's plugins can override any Roda method and call +super+
836
828
  to get the default behavior, which makes Roda very extensible.
@@ -921,8 +913,7 @@ you can then introspect.
921
913
 
922
914
  == Inspiration
923
915
 
924
- Roda was inspired by {Sinatra}[http://www.sinatrarb.com] and {Cuba}[http://cuba.is],
925
- two other Ruby web frameworks.
916
+ Roda was inspired by {Sinatra}[http://www.sinatrarb.com] and {Cuba}[http://cuba.is].
926
917
  It started out as a fork of Cuba, from which it borrows the idea of using a routing tree
927
918
  (which Cuba in turn took from {Rum}[https://github.com/chneukirchen/rum]).
928
919
  From Sinatra, it takes the ideas that route blocks should return the request bodies
data/Rakefile CHANGED
@@ -17,7 +17,7 @@ end
17
17
 
18
18
  ### RDoc
19
19
 
20
- RDOC_DEFAULT_OPTS = ["--line-numbers", "--inline-source", '--title', 'Roda: Routing tree web framework toolkit']
20
+ RDOC_DEFAULT_OPTS = ["--line-numbers", "--inline-source", '--title', 'Roda: Routing tree web toolkit']
21
21
 
22
22
  begin
23
23
  gem 'hanna-nouveau'
@@ -0,0 +1,10 @@
1
+ = New Features
2
+
3
+ * The render plugin now supports :check_paths and :allowed_paths
4
+ options. Setting :check_paths to true will turn on path checking of
5
+ template files. By default, template files are required to be in
6
+ the :views directory, otherwise an exception will be raised. Using
7
+ the :check_paths option can prevent security issues when template
8
+ names are derived from user input. The :allowed_paths option
9
+ overrides which path prefixes are allowed. In Roda 3, :check_paths
10
+ will default to true.
@@ -28,10 +28,14 @@ class Roda
28
28
  #
29
29
  # The following plugin options are supported:
30
30
  #
31
+ # :allowed_paths :: Set the template paths to allow if +:check_paths+ is true.
32
+ # Defaults to the +:views+ directory.
31
33
  # :cache :: nil/false to not cache templates (useful for development), defaults
32
34
  # to true unless RACK_ENV is development to automatically use the
33
35
  # default template cache.
34
36
  # :cache_class :: A class to use as the template cache instead of the default.
37
+ # :check_paths :: Check template paths start with one of the entries in +:allowed_paths+,
38
+ # and raise a RodaError if the path doesn't.
35
39
  # :engine :: The tilt engine to use for rendering, also the default file extension for
36
40
  # templates, defaults to 'erb'.
37
41
  # :escape :: Use Roda's Erubis escaping support, which makes <tt><%= %></tt> escape output,
@@ -137,6 +141,8 @@ class Roda
137
141
  opts = app.opts[:render]
138
142
  opts[:engine] = (opts[:engine] || opts[:ext] || "erb").dup.freeze
139
143
  opts[:views] = File.expand_path(opts[:views]||"views", app.opts[:root]).freeze
144
+ opts[:allowed_paths] ||= [opts[:views]].freeze
145
+ opts[:allowed_paths] = opts[:allowed_paths].map{|f| ::File.expand_path(f)}.uniq.freeze
140
146
 
141
147
  if opts.fetch(:cache, ENV['RACK_ENV'] != 'development')
142
148
  if cache_class = opts[:cache_class]
@@ -352,7 +358,14 @@ class Roda
352
358
 
353
359
  # The template path for the given options.
354
360
  def template_path(opts)
355
- "#{opts[:views]}/#{template_name(opts)}.#{opts[:engine]}"
361
+ path = "#{opts[:views]}/#{template_name(opts)}.#{opts[:engine]}"
362
+ if opts.fetch(:check_paths){render_opts[:check_paths]}
363
+ full_path = ::File.expand_path(path)
364
+ unless render_opts[:allowed_paths].any?{|f| full_path.start_with?(f)}
365
+ raise RodaError, "attempt to render path not in allowed_paths: #{path} (allowed: #{render_opts[:allowed_paths].join(', ')})"
366
+ end
367
+ end
368
+ path
356
369
  end
357
370
 
358
371
  # If a layout should be used, return a hash of options for
@@ -4,7 +4,7 @@ class Roda
4
4
  RodaMajorVersion = 2
5
5
 
6
6
  # The minor version of Roda, updated for new feature releases of Roda.
7
- RodaMinorVersion = 12
7
+ RodaMinorVersion = 13
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
@@ -9,7 +9,7 @@ else
9
9
  describe "render plugin" do
10
10
  before do
11
11
  app(:bare) do
12
- plugin :render, :views=>"./spec/views"
12
+ plugin :render, :views=>"./spec/views", :check_paths=>true
13
13
 
14
14
  route do |r|
15
15
  r.on "home" do
@@ -437,6 +437,62 @@ describe "render plugin" do
437
437
 
438
438
  Class.new(app).render_opts[:cache].must_equal false
439
439
  end
440
+
441
+ it "with :check_paths=>true" do
442
+ render_opts = {}
443
+ app(:bare) do
444
+ plugin :render, :views=>"./spec/views", :check_paths=>true
445
+
446
+ route do |r|
447
+ r.get 'a' do
448
+ render("a", render_opts)
449
+ end
450
+
451
+ r.get 'c' do
452
+ render("about/_test", :locals=>{:title=>'a'})
453
+ end
454
+
455
+ render("b", render_opts)
456
+ end
457
+ end
458
+
459
+ body.strip.must_equal "b"
460
+ req("/a")
461
+ req("/c")
462
+
463
+ app.plugin :render, :allowed_paths=>[]
464
+ proc{req}.must_raise Roda::RodaError
465
+ proc{req("/a")}.must_raise Roda::RodaError
466
+ proc{req("/c")}.must_raise Roda::RodaError
467
+
468
+ app.plugin :render, :allowed_paths=>['spec/views/about']
469
+ proc{req}.must_raise Roda::RodaError
470
+ proc{req("/a")}.must_raise Roda::RodaError
471
+ req("/c")
472
+
473
+ app.plugin :render, :allowed_paths=>%w'spec/views/about spec/views/b'
474
+ body.strip.must_equal "b"
475
+ proc{req("/a")}.must_raise Roda::RodaError
476
+ req("/c")
477
+
478
+ render_opts[:check_paths] = true
479
+ app.plugin :render, :check_paths=>false
480
+ body.strip.must_equal "b"
481
+ proc{req("/a")}.must_raise Roda::RodaError
482
+ req("/c")
483
+
484
+ render_opts.delete(:check_paths)
485
+ app.plugin :render
486
+ body.strip.must_equal "b"
487
+ req("/a")
488
+ req("/c")
489
+
490
+ render_opts[:check_paths] = true
491
+ body.strip.must_equal "b"
492
+ proc{req("/a")}.must_raise Roda::RodaError
493
+ req("/c")
494
+ end
495
+
440
496
  it "with a cache_class set" do
441
497
  app(:bare) do
442
498
  test_cache = Class.new(Roda::RodaCache) do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roda
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.0
4
+ version: 2.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-15 00:00:00.000000000 Z
11
+ date: 2016-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -178,6 +178,7 @@ extra_rdoc_files:
178
178
  - doc/release_notes/2.10.0.txt
179
179
  - doc/release_notes/2.11.0.txt
180
180
  - doc/release_notes/2.12.0.txt
181
+ - doc/release_notes/2.13.0.txt
181
182
  files:
182
183
  - CHANGELOG
183
184
  - MIT-LICENSE
@@ -193,6 +194,7 @@ files:
193
194
  - doc/release_notes/2.10.0.txt
194
195
  - doc/release_notes/2.11.0.txt
195
196
  - doc/release_notes/2.12.0.txt
197
+ - doc/release_notes/2.13.0.txt
196
198
  - doc/release_notes/2.2.0.txt
197
199
  - doc/release_notes/2.3.0.txt
198
200
  - doc/release_notes/2.4.0.txt
@@ -394,5 +396,5 @@ rubyforge_project:
394
396
  rubygems_version: 2.5.1
395
397
  signing_key:
396
398
  specification_version: 4
397
- summary: Routing tree web framework toolkit
399
+ summary: Routing tree web toolkit
398
400
  test_files: []