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