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 +4 -4
- data/CHANGELOG +6 -0
- data/README.rdoc +71 -26
- data/lib/roda/plugins/_erubis_escaping.rb +28 -0
- data/lib/roda/plugins/multi_route.rb +8 -10
- data/lib/roda/plugins/render.rb +15 -1
- data/lib/roda/version.rb +1 -1
- data/spec/plugin/_erubis_escaping_spec.rb +28 -0
- data/spec/plugin/multi_route_spec.rb +4 -4
- data/spec/plugin/render_spec.rb +5 -0
- metadata +17 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1af4812c5c122b1788a1e021e201cd000da9414
|
4
|
+
data.tar.gz: c48935831202f575e8a6032e7f765be91cc00efb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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)
|
data/README.rdoc
CHANGED
@@ -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, :
|
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 <>
|
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
|
-
|
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
|
|
data/lib/roda/plugins/render.rb
CHANGED
@@ -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]
|
data/lib/roda/version.rb
CHANGED
@@ -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 == '<> <>'
|
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"
|
data/spec/plugin/render_spec.rb
CHANGED
@@ -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.
|
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
|