roda-cj 0.9.5 → 0.9.6

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: 4b2651937ad6d2d3c5d87389b03fd9e0f1e3cef2
4
- data.tar.gz: e231917660219dd780e2adaacd5fd8fbbd42afd3
3
+ metadata.gz: b1af4812c5c122b1788a1e021e201cd000da9414
4
+ data.tar.gz: c48935831202f575e8a6032e7f765be91cc00efb
5
5
  SHA512:
6
- metadata.gz: 8ebb628c78058e1e9c61acf148a1e791f3036cf01290461c9ebf01b220b997ab62b78bb2f2429b87b378d1ea0d64134d4a0101ee8dcef5a8794cfe2b6d4effb5
7
- data.tar.gz: db3d4837c8af107e4f3ee6224a15ebadeb5afd0d4122a77f359aa1b9ccb9a263153e5e1628ce77456738f9b76c68fb7cc59a3e5e228dd3c3ba7dd1a84dcc90d6
6
+ metadata.gz: 4c6b474e100d17790346d51b78f8b3ba9d08a600770c58b6a34476c60b1347c17da326428a1ce2e22519258d2efec957be58cc37b945ab4c1fcb5a08c608208c
7
+ data.tar.gz: 91451697eba17949e058401335579b1d915e0b0a6b535df8cc4f480978c3ad5acf804c08fee8e5ac3ea67af6e433f99d87da7c9b844e5ca0a10cc9f323645904
data/CHANGELOG CHANGED
@@ -1,5 +1,11 @@
1
1
  = HEAD
2
2
 
3
+ * Add :content option to view method in render plugin to use given content instead of rendering a template (jeremyevans)
4
+
5
+ * Add :escape option to render plugin for using erb templates where <%= %> escapes and <%== %> does not (jeremyevans)
6
+
7
+ * Make multi_route plugin route("route_name") method a request method instead of an instance method (jeremyevans)
8
+
3
9
  * Add r.multi_route method to multi_route plugin, for dispatching to named route based on first segment in path (jeremyevans)
4
10
 
5
11
  * Allow non-GET requests to use r.redirect with no argument, redirecting to current path (jeremyevans)
@@ -368,31 +368,6 @@ for the response.
368
368
  end
369
369
  end
370
370
 
371
- == Security
372
-
373
- If you want to protect against some common web application
374
- vulnerabilities, you can use
375
- {Rack::Protection}[https://github.com/rkh/rack-protection].
376
- It is not included by default because there are legitimate
377
- uses for plain Roda (for instance, when designing an API).
378
-
379
- If you are using sessions, you should also always set a session
380
- secret to some undisclosed value. Keep in mind that the content
381
- in the session cookie is not encrypted, just signed to prevent
382
- tampering.
383
-
384
- require "roda"
385
- require "rack/protection"
386
-
387
- class App < Roda
388
- use Rack::Session::Cookie, :secret => ENV['SECRET']
389
- use Rack::Protection
390
-
391
- route do |r|
392
- # ...
393
- end
394
- end
395
-
396
371
  == Verb Methods
397
372
 
398
373
  The main match method is +r.on+, but as displayed above, you can also
@@ -617,12 +592,82 @@ You can override the default rendering options by passing a hash to the plugin,
617
592
  or modifying the +render_opts+ hash after loading the plugin:
618
593
 
619
594
  class App < Roda
620
- plugin :render, :engine=>'slim' # Tilt engine/template file extension to use
595
+ plugin :render, :escape => true # Automatically escape output in erb templates
621
596
  render_opts[:views] = 'admin_views' # Default views directory
622
597
  render_opts[:layout] = "admin_layout" # Default layout template
623
598
  render_opts[:layout_opts] = {:engine=>'haml'} # Default layout template options
624
599
  render_opts[:opts] = {:default_encoding=>'UTF-8'} # Default template options
625
600
  render_opts[:cache] = false # Disable template caching
601
+ render_opts[:engine] = 'slim' # Tilt engine/template file extension to use
602
+ end
603
+
604
+ == Sessions
605
+
606
+ By default, Roda doesn't turn on sessions, but most users are going to
607
+ want to turn on session support, and the simplest way to do that is to
608
+ use the <tt>Rack::Session::Cookie</tt> middleware that comes with rack:
609
+
610
+ require "roda"
611
+
612
+ class App < Roda
613
+ use Rack::Session::Cookie, :secret => ENV['SECRET']
614
+ end
615
+
616
+ == Security
617
+
618
+ Web application security is a very large topic, but here are some
619
+ things you can do with Roda to prevent some common web application
620
+ vulnerabilities.
621
+
622
+ === Session Security
623
+
624
+ If you are using sessions, you should also always set a session
625
+ secret using the +:secret+ option as shown above. Make sure this
626
+ secret is not disclosed, because if an attacker knows the +:secret+
627
+ value, they can inject arbitrary session values, which in the worst case
628
+ scenario can lead to remote code execution.
629
+
630
+ Keep in mind that with <tt>Rack::Session::Cookie</tt>, the content in
631
+ the session cookie is not encrypted, just signed to prevent tampering.
632
+ This means you should not store any data in the session that itself is
633
+ secret.
634
+
635
+ === Cross Site Request Forgery (CSRF)
636
+
637
+ CSRF can be prevented by using the +csrf+ plugin that ships with Roda,
638
+ which uses the {rack_csrf}[https://github.com/baldowl/rack_csrf]
639
+ library. Just make sure that you include the CSRF token tags in your
640
+ html as appropriate.
641
+
642
+ It's also possible to use the <tt>Rack::Csrf</tt> middleware directly,
643
+ you don't have to use the +csrf+ plugin.
644
+
645
+ === Cross Site Scripting (XSS)
646
+
647
+ The easiest way to prevent XSS with Roda is to use a template library
648
+ that automatically escapes output by default. The +:escape+ option
649
+ to the render plugin sets the ERB template processor to escape by
650
+ default, so that in your templates:
651
+
652
+ <%= '<>' %> # outputs &lt;&gt;
653
+ <%== '<>' %> # outputs <>
654
+
655
+ Note that unlike most other render options, the :escape option
656
+ must be passed to the <tt>plugin :render</tt> call, it won't be
657
+ respected if added later.
658
+
659
+ === Other
660
+
661
+ For prevention of some other vulnerabilities, such as click-jacking,
662
+ directory traversal, session hijacking, and IP spoofing, consider using
663
+ {Rack::Protection}[https://github.com/rkh/rack-protection], which is
664
+ a rack middleware that can be added the usual way:
665
+
666
+ require 'roda'
667
+ require 'rack/protection'
668
+
669
+ class App < Roda
670
+ use Rack::Protection
626
671
  end
627
672
 
628
673
  == Plugins
@@ -0,0 +1,28 @@
1
+ require 'erubis'
2
+
3
+ class Roda
4
+ module RodaPlugins
5
+ # The _erubis_escaping plugin is an internal plugin that provides a
6
+ # subclass of Erubis::EscapedEruby with a bugfix and an optimization.
7
+ module ErubisEscaping
8
+ # Optimized subclass that fixes escaping of postfix conditionals.
9
+ class Eruby < Erubis::EscapedEruby
10
+ # Set escaping class to a local variable, so you don't need a
11
+ # constant lookup per escape.
12
+ def convert_input(codebuf, input)
13
+ codebuf << '_erubis_xml_helper = Erubis::XmlHelper;'
14
+ super
15
+ end
16
+
17
+ # Fix bug in Erubis::EscapedEruby where postfix conditionals inside
18
+ # <%= %> are broken (e.g. <%= foo if bar %> ), and optimize by using
19
+ # a local variable instead of a constant lookup.
20
+ def add_expr_escaped(src, code)
21
+ src << " #{@bufvar} << _erubis_xml_helper.escape_xml((" << code << '));'
22
+ end
23
+ end
24
+ end
25
+
26
+ register_plugin(:_erubis_escaping, ErubisEscaping)
27
+ end
28
+ end
@@ -32,11 +32,11 @@ class Roda
32
32
  # # or
33
33
  #
34
34
  # r.on "foo" do
35
- # route 'foo'
35
+ # r.route 'foo'
36
36
  # end
37
37
  #
38
38
  # r.on "bar" do
39
- # route 'bar'
39
+ # r.route 'bar'
40
40
  # end
41
41
  # end
42
42
  #
@@ -86,13 +86,6 @@ class Roda
86
86
  end
87
87
  end
88
88
 
89
- module InstanceMethods
90
- # Dispatch to the named route with the given name.
91
- def route(name)
92
- instance_exec(request, &self.class.named_route(name))
93
- end
94
- end
95
-
96
89
  module RequestClassMethods
97
90
  # A regexp matching any of the current named routes.
98
91
  def named_route_regexp
@@ -107,10 +100,15 @@ class Roda
107
100
  # is given, yield to the block.
108
101
  def multi_route
109
102
  on self.class.named_route_regexp do |section|
110
- scope.route(section)
103
+ route(section)
111
104
  yield if block_given?
112
105
  end
113
106
  end
107
+
108
+ # Dispatch to the named route with the given name.
109
+ def route(name)
110
+ scope.instance_exec(self, &self.class.roda_class.named_route(name))
111
+ end
114
112
  end
115
113
  end
116
114
 
@@ -30,6 +30,8 @@ class Roda
30
30
  # :cache :: nil/false to not cache templates (useful for development), defaults
31
31
  # to true to automatically use the default template cache.
32
32
  # :engine :: The tilt engine to use for rendering, defaults to 'erb'.
33
+ # :escape :: Use Roda's Erubis escaping support, which handles postfix
34
+ # conditions inside <%= %> tags.
33
35
  # :ext :: The file extension to assume for view files, defaults to the :engine
34
36
  # option.
35
37
  # :layout :: The base name of the layout file, defaults to 'layout'.
@@ -49,6 +51,9 @@ class Roda
49
51
  # There are a couple of additional options to +view+ and +render+ that are
50
52
  # available at runtime:
51
53
  #
54
+ # :content :: Only respected by +view+, provides the content to render
55
+ # inside the layout, instead of rendering a template to get
56
+ # the content.
52
57
  # :inline :: Use the value given as the template code, instead of looking
53
58
  # for template code in a file.
54
59
  # :locals :: Hash of local variables to make available inside the template.
@@ -64,6 +69,12 @@ class Roda
64
69
  # If you pass a hash as the first argument to +view+ or +render+, it should
65
70
  # have either +:inline+ or +:path+ as one of the keys.
66
71
  module Render
72
+ def self.load_dependencies(app, opts={})
73
+ if opts[:escape]
74
+ app.plugin :_erubis_escaping
75
+ end
76
+ end
77
+
67
78
  # Setup default rendering options. See Render for details.
68
79
  def self.configure(app, opts={})
69
80
  if app.opts[:render]
@@ -83,6 +94,9 @@ class Roda
83
94
  if RUBY_VERSION >= "1.9"
84
95
  opts[:opts][:default_encoding] ||= Encoding.default_external
85
96
  end
97
+ if opts[:escape]
98
+ opts[:opts][:engine_class] = ErubisEscaping::Eruby
99
+ end
86
100
  opts[:cache] = app.thread_safe_cache if opts.fetch(:cache, true)
87
101
  end
88
102
 
@@ -149,7 +163,7 @@ class Roda
149
163
  end
150
164
  end
151
165
 
152
- content = render(template, opts)
166
+ content = opts[:content] || render(template, opts)
153
167
 
154
168
  if layout = opts.fetch(:layout, render_opts[:layout])
155
169
  if layout_opts = opts[:layout_opts]
@@ -1,3 +1,3 @@
1
1
  class Roda
2
- RodaVersion = '0.9.5'.freeze
2
+ RodaVersion = '0.9.6'.freeze
3
3
  end
@@ -0,0 +1,28 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ begin
4
+ require 'tilt/erb'
5
+ begin
6
+ require 'tilt/erubis'
7
+ rescue LoadError
8
+ # Tilt 1 support
9
+ end
10
+ rescue LoadError
11
+ warn "tilt or erubis not installed, skipping _erubis_escaping plugin test"
12
+ else
13
+ describe "_erubis_escaping plugin" do
14
+ before do
15
+ app(:bare) do
16
+ plugin :render, :escape=>true
17
+
18
+ route do |r|
19
+ render(:inline=>'<%= "<>" %> <%== "<>" %><%= "<>" if false %>')
20
+ end
21
+ end
22
+ end
23
+
24
+ it "should escape inside <%= %> and not inside <%== %>, and handle postfix conditionals" do
25
+ body.should == '&lt;&gt; <>'
26
+ end
27
+ end
28
+ end
@@ -33,7 +33,7 @@ describe "multi_route plugin" do
33
33
  end
34
34
 
35
35
  r.get do
36
- route("get")
36
+ r.route("get")
37
37
 
38
38
  r.is "b" do
39
39
  "getb"
@@ -41,7 +41,7 @@ describe "multi_route plugin" do
41
41
  end
42
42
 
43
43
  r.post do
44
- route("post")
44
+ r.route("post")
45
45
 
46
46
  r.is "b" do
47
47
  "postb"
@@ -87,14 +87,14 @@ describe "multi_route plugin" do
87
87
  @app = Class.new(@app)
88
88
  @app.route do |r|
89
89
  r.get do
90
- route("post")
90
+ r.route("post")
91
91
 
92
92
  r.is "b" do
93
93
  "1b"
94
94
  end
95
95
  end
96
96
  r.post do
97
- route("get")
97
+ r.route("get")
98
98
 
99
99
  r.is "b" do
100
100
  "2b"
@@ -28,6 +28,10 @@ describe "render plugin" do
28
28
  r.on "path" do
29
29
  render(:path=>"./spec/views/about.erb", :locals=>{:title => "Path"}, :layout_opts=>{:locals=>{:title=>"Home"}})
30
30
  end
31
+
32
+ r.on "content" do
33
+ view(:content=>'bar', :layout_opts=>{:locals=>{:title=>"Home"}})
34
+ end
31
35
  end
32
36
  end
33
37
  end
@@ -37,6 +41,7 @@ describe "render plugin" do
37
41
  body("/home").strip.should == "<title>Roda: Home</title>\n<h1>Home</h1>\n<p>Hello Agent Smith</p>"
38
42
  body("/inline").strip.should == "Hello Agent Smith"
39
43
  body("/path").strip.should == "<h1>Path</h1>"
44
+ body("/content").strip.should == "<title>Roda: Home</title>\nbar"
40
45
  end
41
46
 
42
47
  it "with str as engine" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roda-cj
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: erubis
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rack_csrf
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +108,7 @@ files:
94
108
  - lib/roda/plugins/header_matchers.rb
95
109
  - lib/roda/plugins/per_thread_caching.rb
96
110
  - lib/roda/plugins/error_handler.rb
111
+ - lib/roda/plugins/_erubis_escaping.rb
97
112
  - lib/roda/plugins/indifferent_params.rb
98
113
  - lib/roda/plugins/head.rb
99
114
  - lib/roda/plugins/json.rb
@@ -130,6 +145,7 @@ files:
130
145
  - spec/plugin/csrf_spec.rb
131
146
  - spec/plugin/default_headers_spec.rb
132
147
  - spec/plugin/backtracking_array_spec.rb
148
+ - spec/plugin/_erubis_escaping_spec.rb
133
149
  - spec/plugin/per_thread_caching_spec.rb
134
150
  - spec/plugin/content_for_spec.rb
135
151
  - spec/plugin/hooks_spec.rb