roda-cj 0.9.5 → 0.9.6

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.
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