cuba 3.3.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gems +3 -3
- data/CHANGELOG +5 -0
- data/LICENSE +5 -1
- data/README.md +96 -12
- data/cuba.gemspec +1 -1
- data/lib/cuba.rb +47 -3
- data/lib/cuba/render.rb +1 -0
- data/lib/cuba/safe.rb +23 -0
- data/lib/cuba/safe/csrf.rb +47 -0
- data/lib/cuba/safe/secure_headers.rb +40 -0
- data/test/csrf.rb +139 -0
- data/test/render.rb +15 -0
- data/test/safe.rb +74 -0
- data/test/with.rb +42 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33341fdef71be26c9506be1f85b0d223721baaf3
|
4
|
+
data.tar.gz: f78025b8496068b945a4095a51115dbb9d939c08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 933e16d3505eca916f1d86fbb36aaf2b58fc87256272b326d0ca52afcbd3dbc699e19bae18a4f5191d05194c53b12b882983e64240ab493691445613db2c327f
|
7
|
+
data.tar.gz: fa31afdad6c4f18337c88f5a4fd896f6585d972c53a92ca2e469bbe8eafcbe53927246e99fa46e09ce0d51a28d36628aa702cabb74d98215b3e6bec06e6157e9
|
data/.gems
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
cutest -v 1.2.
|
2
|
-
rack -v 1.
|
1
|
+
cutest -v 1.2.2
|
2
|
+
rack -v 1.6.0
|
3
3
|
tilt -v 2.0.1
|
4
|
-
rack-test -v 0.6.
|
4
|
+
rack-test -v 0.6.3
|
data/CHANGELOG
CHANGED
data/LICENSE
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
Copyright (
|
1
|
+
Copyright (C) 2008-2009 Christian Neukirchen
|
2
|
+
Copyright (c) 2010-2015 Michel Martens
|
3
|
+
Copyright (c) 2010-2015 Damian Janowski
|
4
|
+
Copyright (c) 2010-2015 Cyril David
|
5
|
+
Copyright (c) 2013-2015 Francesco Rodríguez
|
2
6
|
|
3
7
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
8
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -217,7 +217,7 @@ Cuba.define do
|
|
217
217
|
on get do
|
218
218
|
on "hello" do
|
219
219
|
on root do
|
220
|
-
|
220
|
+
res.write "hello world"
|
221
221
|
end
|
222
222
|
end
|
223
223
|
end
|
@@ -274,36 +274,120 @@ end
|
|
274
274
|
Security
|
275
275
|
--------
|
276
276
|
|
277
|
-
The
|
278
|
-
|
277
|
+
The most important security consideration is to use `https` for all
|
278
|
+
requests. If that's not the case, any attempt to secure the application
|
279
|
+
could be in vain. The rest of this section assumes `https` is
|
280
|
+
enforced.
|
281
|
+
|
282
|
+
When building a web application, you need to include a security
|
283
|
+
layer. Cuba ships with the `Cuba::Safe` plugin, which applies several
|
284
|
+
security related headers to prevent attacks like clickjacking and
|
285
|
+
cross-site scripting, among others. It is not included by default
|
279
286
|
because there are legitimate uses for plain Cuba (for instance,
|
280
287
|
when designing an API).
|
281
288
|
|
282
|
-
|
283
|
-
|
284
|
-
|
289
|
+
Here's how to include it:
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
Cuba.plugin(Cuba::Safe)
|
293
|
+
```
|
285
294
|
|
286
295
|
You should also always set a session secret to some undisclosed
|
287
296
|
value. Keep in mind that the content in the session cookie is
|
288
297
|
*not* encrypted.
|
289
298
|
|
290
|
-
[rack-protection]: https://github.com/rkh/rack-protection
|
291
|
-
|
292
299
|
``` ruby
|
300
|
+
Cuba.use(Rack::Session::Cookie, :secret => "__a_very_long_string__")
|
301
|
+
```
|
302
|
+
|
303
|
+
In the end, your application should look like this:
|
304
|
+
|
305
|
+
```ruby
|
293
306
|
require "cuba"
|
294
|
-
require "rack/protection"
|
295
307
|
|
296
308
|
Cuba.use Rack::Session::Cookie, :secret => "__a_very_long_string__"
|
297
|
-
|
298
|
-
Cuba.
|
309
|
+
|
310
|
+
Cuba.plugin Cuba::Safe
|
299
311
|
|
300
312
|
Cuba.define do
|
313
|
+
on csrf.unsafe? do
|
314
|
+
csrf.reset!
|
315
|
+
|
316
|
+
res.status = 403
|
317
|
+
res.write("Not authorized")
|
318
|
+
|
319
|
+
halt(res.finish)
|
320
|
+
end
|
301
321
|
|
302
322
|
# Now your app is protected against a wide range of attacks.
|
303
323
|
...
|
304
324
|
end
|
305
325
|
```
|
306
326
|
|
327
|
+
The `Cuba::Safe` plugin is composed of two modules:
|
328
|
+
|
329
|
+
* `Cuba::Safe::SecureHeaders`
|
330
|
+
* `Cuba::Safe::CSRF`
|
331
|
+
|
332
|
+
You can include them individually, but while the modularity is good
|
333
|
+
for development, it's very common to use them in tandem. As that's
|
334
|
+
the normal use case, including `Cuba::Safe` is the preferred way.
|
335
|
+
|
336
|
+
Cross-Site Request Forgery
|
337
|
+
--------------------------
|
338
|
+
|
339
|
+
The `Cuba::Safe::CSRF` plugin provides a `csrf` object with the
|
340
|
+
following methods:
|
341
|
+
|
342
|
+
* `token`: the current security token.
|
343
|
+
* `reset!`: forces the token to be recreated.
|
344
|
+
* `safe?`: returns `true` if the request is safe.
|
345
|
+
* `unsafe?`: returns `true` if the request is unsafe.
|
346
|
+
* `form_tag`: returns a string with the `csrf_token` hidden input tag.
|
347
|
+
* `meta_tag`: returns a string with the `csrf_token` meta tag.
|
348
|
+
|
349
|
+
Here's an example of how to use it:
|
350
|
+
|
351
|
+
```ruby
|
352
|
+
Cuba.plugin(Cuba::Safe)
|
353
|
+
|
354
|
+
Cuba.define do
|
355
|
+
on csrf.unsafe? do
|
356
|
+
csrf.reset!
|
357
|
+
|
358
|
+
res.status = 403
|
359
|
+
res.write("Not authorized")
|
360
|
+
|
361
|
+
halt(res.finish)
|
362
|
+
end
|
363
|
+
|
364
|
+
# Here comes the rest of your application
|
365
|
+
# ...
|
366
|
+
end
|
367
|
+
```
|
368
|
+
|
369
|
+
You have to include `csrf.form_tag` in your forms and `csrf.meta_tag`
|
370
|
+
among your meta tags. Here's an example that assumes you are using
|
371
|
+
`Cuba::Mote` from `cuba-contrib`:
|
372
|
+
|
373
|
+
```html
|
374
|
+
<!DOCTYPE html>
|
375
|
+
<html>
|
376
|
+
<head>
|
377
|
+
{{ this.csrf.meta_tag }}
|
378
|
+
...
|
379
|
+
</head>
|
380
|
+
...
|
381
|
+
<body>
|
382
|
+
<form action="/foo" method="POST">
|
383
|
+
{{ this.csrf.form_tag }}
|
384
|
+
...
|
385
|
+
</form>
|
386
|
+
...
|
387
|
+
</body>
|
388
|
+
</html>
|
389
|
+
```
|
390
|
+
|
307
391
|
HTTP Verbs
|
308
392
|
----------
|
309
393
|
|
@@ -370,7 +454,7 @@ In the second case, the substring `:id` gets replaced by `([^\\/]+)` and the
|
|
370
454
|
string becomes `"users/([^\\/]+)"` before performing the match, thus it reverts
|
371
455
|
to the first form we saw.
|
372
456
|
|
373
|
-
In the third case, the symbol
|
457
|
+
In the third case, the symbol ––no matter what it says––gets replaced
|
374
458
|
by `"([^\\/]+)"`, and again we are in presence of case 1.
|
375
459
|
|
376
460
|
The fourth case, again, reverts to the basic matcher: it generates the string
|
data/cuba.gemspec
CHANGED
data/lib/cuba.rb
CHANGED
@@ -8,8 +8,8 @@ class Cuba
|
|
8
8
|
attr :body
|
9
9
|
attr :headers
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
@status =
|
11
|
+
def initialize(headers = {})
|
12
|
+
@status = nil
|
13
13
|
@headers = headers
|
14
14
|
@body = []
|
15
15
|
@length = 0
|
@@ -114,7 +114,7 @@ class Cuba
|
|
114
114
|
def call!(env)
|
115
115
|
@env = env
|
116
116
|
@req = settings[:req].new(env)
|
117
|
-
@res = settings[:res].new
|
117
|
+
@res = settings[:res].new(settings[:default_headers].dup)
|
118
118
|
|
119
119
|
# This `catch` statement will either receive a
|
120
120
|
# rack response tuple via a `halt`, or will
|
@@ -339,7 +339,51 @@ class Cuba
|
|
339
339
|
def halt(response)
|
340
340
|
throw :halt, response
|
341
341
|
end
|
342
|
+
|
343
|
+
# Adds ability to pass information to a nested Cuba application.
|
344
|
+
# It receives two parameters: a hash that represents the passed
|
345
|
+
# information and a block. The #vars method is used to retrieve
|
346
|
+
# a hash with the passed information.
|
347
|
+
#
|
348
|
+
# class Platforms < Cuba
|
349
|
+
# define do
|
350
|
+
# platform = vars[:platform]
|
351
|
+
#
|
352
|
+
# on default do
|
353
|
+
# res.write(platform) # => "heroku" or "salesforce"
|
354
|
+
# end
|
355
|
+
# end
|
356
|
+
# end
|
357
|
+
#
|
358
|
+
# Cuba.define do
|
359
|
+
# on "(heroku|salesforce)" do |platform|
|
360
|
+
# with(platform: platform) do
|
361
|
+
# run(Platforms)
|
362
|
+
# end
|
363
|
+
# end
|
364
|
+
# end
|
365
|
+
#
|
366
|
+
def with(dict = {})
|
367
|
+
old, env["cuba.vars"] = vars, vars.merge(dict)
|
368
|
+
yield
|
369
|
+
ensure
|
370
|
+
env["cuba.vars"] = old
|
371
|
+
end
|
372
|
+
|
373
|
+
# Returns a hash with the information set by the #with method.
|
374
|
+
#
|
375
|
+
# with(role: "admin", site: "main") do
|
376
|
+
# on default do
|
377
|
+
# res.write(vars.inspect)
|
378
|
+
# end
|
379
|
+
# end
|
380
|
+
# # => '{:role=>"admin", :site=>"main"}'
|
381
|
+
#
|
382
|
+
def vars
|
383
|
+
env["cuba.vars"] ||= {}
|
384
|
+
end
|
342
385
|
end
|
343
386
|
|
344
387
|
Cuba.settings[:req] = Rack::Request
|
345
388
|
Cuba.settings[:res] = Cuba::Response
|
389
|
+
Cuba.settings[:default_headers] = {}
|
data/lib/cuba/render.rb
CHANGED
data/lib/cuba/safe.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative "safe/csrf"
|
2
|
+
require_relative "safe/secure_headers"
|
3
|
+
|
4
|
+
class Cuba
|
5
|
+
# == Cuba::Safe
|
6
|
+
#
|
7
|
+
# This plugin contains security related features for Cuba
|
8
|
+
# applications. It takes ideas from secureheaders[1].
|
9
|
+
#
|
10
|
+
# == Usage
|
11
|
+
#
|
12
|
+
# require "cuba"
|
13
|
+
# require "cuba/safe"
|
14
|
+
#
|
15
|
+
# Cuba.plugin(Cuba::Safe)
|
16
|
+
#
|
17
|
+
module Safe
|
18
|
+
def self.setup(app)
|
19
|
+
app.plugin(Safe::SecureHeaders)
|
20
|
+
app.plugin(Safe::CSRF)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Cuba
|
2
|
+
module Safe
|
3
|
+
module CSRF
|
4
|
+
def csrf
|
5
|
+
@csrf ||= Cuba::Safe::CSRF::Helper.new(req)
|
6
|
+
end
|
7
|
+
|
8
|
+
class Helper
|
9
|
+
attr :req
|
10
|
+
|
11
|
+
def initialize(req)
|
12
|
+
@req = req
|
13
|
+
end
|
14
|
+
|
15
|
+
def token
|
16
|
+
session[:csrf_token] ||= SecureRandom.base64(32)
|
17
|
+
end
|
18
|
+
|
19
|
+
def reset!
|
20
|
+
session.delete(:csrf_token)
|
21
|
+
end
|
22
|
+
|
23
|
+
def safe?
|
24
|
+
return req.get? || req.head? ||
|
25
|
+
req[:csrf_token] == token ||
|
26
|
+
req.env["HTTP_X_CSRF_TOKEN"] == token
|
27
|
+
end
|
28
|
+
|
29
|
+
def unsafe?
|
30
|
+
return !safe?
|
31
|
+
end
|
32
|
+
|
33
|
+
def form_tag
|
34
|
+
return %Q(<input type="hidden" name="csrf_token" value="#{ token }">)
|
35
|
+
end
|
36
|
+
|
37
|
+
def meta_tag
|
38
|
+
return %Q(<meta name="csrf_token" content="#{ token }">)
|
39
|
+
end
|
40
|
+
|
41
|
+
def session
|
42
|
+
return req.env["rack.session"]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# == Secure HTTP Headers
|
2
|
+
#
|
3
|
+
# This plugin will automatically apply several headers that are
|
4
|
+
# related to security. This includes:
|
5
|
+
#
|
6
|
+
# - HTTP Strict Transport Security (HSTS) [2].
|
7
|
+
# - X-Frame-Options [3].
|
8
|
+
# - X-XSS-Protection [4].
|
9
|
+
# - X-Content-Type-Options [5].
|
10
|
+
# - X-Download-Options [6].
|
11
|
+
# - X-Permitted-Cross-Domain-Policies [7].
|
12
|
+
#
|
13
|
+
# == References
|
14
|
+
#
|
15
|
+
# [1]: https://github.com/twitter/secureheaders
|
16
|
+
# [2]: https://tools.ietf.org/html/rfc6797
|
17
|
+
# [3]: https://tools.ietf.org/html/draft-ietf-websec-x-frame-options-02
|
18
|
+
# [4]: http://msdn.microsoft.com/en-us/library/dd565647(v=vs.85).aspx
|
19
|
+
# [5]: http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx
|
20
|
+
# [6]: http://msdn.microsoft.com/en-us/library/ie/jj542450(v=vs.85).aspx
|
21
|
+
# [7]: https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html
|
22
|
+
#
|
23
|
+
class Cuba
|
24
|
+
module Safe
|
25
|
+
module SecureHeaders
|
26
|
+
HEADERS = {
|
27
|
+
"X-Content-Type-Options" => "nosniff",
|
28
|
+
"X-Download-Options" => "noopen",
|
29
|
+
"X-Frame-Options" => "SAMEORIGIN",
|
30
|
+
"X-Permitted-Cross-Domain-Policies" => "none",
|
31
|
+
"X-XSS-Protection" => "1; mode=block",
|
32
|
+
"Strict-Transport-Security" => "max-age=631138519; includeSubdomains; preload"
|
33
|
+
}
|
34
|
+
|
35
|
+
def self.setup(app)
|
36
|
+
app.settings[:default_headers].merge!(HEADERS)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/test/csrf.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
require "cuba/safe/csrf"
|
3
|
+
require "cuba/test"
|
4
|
+
|
5
|
+
def assert_no_raise
|
6
|
+
yield
|
7
|
+
success
|
8
|
+
end
|
9
|
+
|
10
|
+
class UnsafeRequest < RuntimeError; end
|
11
|
+
|
12
|
+
scope do
|
13
|
+
setup do
|
14
|
+
Cuba.reset!
|
15
|
+
|
16
|
+
Cuba.use(Rack::Session::Cookie, secret: "_this_must_be_secret")
|
17
|
+
Cuba.plugin(Cuba::Safe::CSRF)
|
18
|
+
end
|
19
|
+
|
20
|
+
test "safe http methods" do
|
21
|
+
Cuba.define do
|
22
|
+
raise UnsafeRequest if csrf.unsafe?
|
23
|
+
end
|
24
|
+
|
25
|
+
assert_no_raise do
|
26
|
+
get "/"
|
27
|
+
head "/"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
test "invalid csrf param" do
|
32
|
+
Cuba.define do
|
33
|
+
if csrf.unsafe?
|
34
|
+
csrf.reset!
|
35
|
+
end
|
36
|
+
|
37
|
+
res.write(csrf.token)
|
38
|
+
end
|
39
|
+
|
40
|
+
get "/"
|
41
|
+
|
42
|
+
old_token = last_response.body
|
43
|
+
|
44
|
+
post "/", "csrf_token" => "nonsense"
|
45
|
+
|
46
|
+
new_token = last_response.body
|
47
|
+
|
48
|
+
assert(old_token != new_token)
|
49
|
+
end
|
50
|
+
|
51
|
+
test "valid csrf param" do
|
52
|
+
Cuba.define do
|
53
|
+
raise unless csrf.safe?
|
54
|
+
|
55
|
+
on get do
|
56
|
+
res.write(csrf.token)
|
57
|
+
end
|
58
|
+
|
59
|
+
on post do
|
60
|
+
res.write("safe")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
get "/"
|
65
|
+
|
66
|
+
csrf_token = last_response.body
|
67
|
+
|
68
|
+
assert(!csrf_token.empty?)
|
69
|
+
|
70
|
+
assert_no_raise do
|
71
|
+
post "/", "csrf_token" => csrf_token
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
test "http header" do
|
76
|
+
csrf_token = SecureRandom.hex(32)
|
77
|
+
|
78
|
+
Cuba.define do
|
79
|
+
session[:csrf_token] = csrf_token
|
80
|
+
raise if csrf.unsafe?
|
81
|
+
end
|
82
|
+
|
83
|
+
assert_no_raise do
|
84
|
+
post "/", {}, { "HTTP_X_CSRF_TOKEN" => csrf_token }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
test "sub app raises too" do
|
89
|
+
class App < Cuba
|
90
|
+
define do
|
91
|
+
on post do
|
92
|
+
res.write("unsafe")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
Cuba.define do
|
98
|
+
raise UnsafeRequest unless csrf.safe?
|
99
|
+
|
100
|
+
on "app" do
|
101
|
+
run(App)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
assert_raise(UnsafeRequest) do
|
106
|
+
post "/app"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
test "only sub app" do
|
111
|
+
class App < Cuba
|
112
|
+
define do
|
113
|
+
raise UnsafeRequest unless csrf.safe?
|
114
|
+
|
115
|
+
on post do
|
116
|
+
res.write("unsafe")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
Cuba.define do
|
122
|
+
on "app" do
|
123
|
+
run(App)
|
124
|
+
end
|
125
|
+
|
126
|
+
on default do
|
127
|
+
res.write("safe")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
assert_no_raise do
|
132
|
+
post "/"
|
133
|
+
end
|
134
|
+
|
135
|
+
assert_raise(UnsafeRequest) do
|
136
|
+
post "/app"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/test/render.rb
CHANGED
@@ -111,3 +111,18 @@ test "overrides layout" do
|
|
111
111
|
|
112
112
|
assert_response body, ["<title>Alternative Layout: Home</title>\n<h1>Home</h1>\n<p>Hello Agent Smith</p>\n"]
|
113
113
|
end
|
114
|
+
|
115
|
+
test "ensures content-type header is set" do
|
116
|
+
Cuba.plugin(Cuba::Render)
|
117
|
+
|
118
|
+
Cuba.define do
|
119
|
+
on default do
|
120
|
+
res.status = 403
|
121
|
+
render("about", title: "Hello Cuba")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
_, headers, _ = Cuba.call({})
|
126
|
+
|
127
|
+
assert_equal("text/html; charset=utf-8", headers["Content-Type"])
|
128
|
+
end
|
data/test/safe.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
require "cuba/safe"
|
3
|
+
|
4
|
+
scope do
|
5
|
+
test "secure headers" do
|
6
|
+
Cuba.plugin(Cuba::Safe)
|
7
|
+
|
8
|
+
class Hello < Cuba
|
9
|
+
define do
|
10
|
+
on root do
|
11
|
+
res.write("hello")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Cuba.define do
|
17
|
+
on root do
|
18
|
+
res.write("home")
|
19
|
+
end
|
20
|
+
|
21
|
+
on "hello" do
|
22
|
+
run(Hello)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
secure_headers = Cuba::Safe::SecureHeaders::HEADERS
|
27
|
+
|
28
|
+
_, headers, _ = Cuba.call("PATH_INFO" => "/", "SCRIPT_NAME" => "/")
|
29
|
+
secure_headers.each do |header, value|
|
30
|
+
assert_equal(value, headers[header])
|
31
|
+
end
|
32
|
+
|
33
|
+
_, headers, _ = Cuba.call("PATH_INFO" => "/hello", "SCRIPT_NAME" => "/")
|
34
|
+
secure_headers.each do |header, value|
|
35
|
+
assert_equal(value, headers[header])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
test "secure headers only in sub app" do
|
40
|
+
Cuba.settings[:default_headers] = {}
|
41
|
+
|
42
|
+
class About < Cuba
|
43
|
+
plugin(Cuba::Safe)
|
44
|
+
|
45
|
+
define do
|
46
|
+
on root do
|
47
|
+
res.write("about")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
Cuba.define do
|
53
|
+
on root do
|
54
|
+
res.write("home")
|
55
|
+
end
|
56
|
+
|
57
|
+
on "about" do
|
58
|
+
run(About)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
secure_headers = Cuba::Safe::SecureHeaders::HEADERS
|
63
|
+
|
64
|
+
_, headers, _ = Cuba.call("PATH_INFO" => "/", "SCRIPT_NAME" => "/")
|
65
|
+
secure_headers.each do |header, _|
|
66
|
+
assert(!headers.key?(header))
|
67
|
+
end
|
68
|
+
|
69
|
+
_, headers, _ = Cuba.call("PATH_INFO" => "/about", "SCRIPT_NAME" => "/")
|
70
|
+
secure_headers.each do |header, value|
|
71
|
+
assert_equal(value, headers[header])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/test/with.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
test do
|
4
|
+
class UserPhotos < Cuba
|
5
|
+
define do
|
6
|
+
on root do
|
7
|
+
res.write "uid: %d" % vars[:user_id]
|
8
|
+
res.write "site: %s" % vars[:site]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Photos < Cuba
|
14
|
+
define do
|
15
|
+
on ":id/photos" do |id|
|
16
|
+
with user_id: id do
|
17
|
+
_, _, body = UserPhotos.call(req.env)
|
18
|
+
|
19
|
+
body.each do |line|
|
20
|
+
res.write line
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
res.write vars.inspect
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Cuba.define do
|
30
|
+
on "users" do
|
31
|
+
with user_id: "default", site: "main" do
|
32
|
+
run Photos
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
_, _, body = Cuba.call({ "PATH_INFO" => "/users/1001/photos",
|
38
|
+
"SCRIPT_NAME" => "" })
|
39
|
+
|
40
|
+
assert_response body, ["uid: 1001", "site: main",
|
41
|
+
'{:user_id=>"default", :site=>"main"}']
|
42
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cuba
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michel Martens
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -87,12 +87,16 @@ files:
|
|
87
87
|
- lib/cuba.rb
|
88
88
|
- lib/cuba/capybara.rb
|
89
89
|
- lib/cuba/render.rb
|
90
|
+
- lib/cuba/safe.rb
|
91
|
+
- lib/cuba/safe/csrf.rb
|
92
|
+
- lib/cuba/safe/secure_headers.rb
|
90
93
|
- lib/cuba/test.rb
|
91
94
|
- makefile
|
92
95
|
- test/accept.rb
|
93
96
|
- test/captures.rb
|
94
97
|
- test/composition.rb
|
95
98
|
- test/cookie.rb
|
99
|
+
- test/csrf.rb
|
96
100
|
- test/extension.rb
|
97
101
|
- test/helper.rb
|
98
102
|
- test/host.rb
|
@@ -109,6 +113,7 @@ files:
|
|
109
113
|
- test/render.rb
|
110
114
|
- test/root.rb
|
111
115
|
- test/run.rb
|
116
|
+
- test/safe.rb
|
112
117
|
- test/segment.rb
|
113
118
|
- test/session.rb
|
114
119
|
- test/settings.rb
|
@@ -126,6 +131,7 @@ files:
|
|
126
131
|
- test/views/layout.mote
|
127
132
|
- test/views/layout.str
|
128
133
|
- test/views/test.erb
|
134
|
+
- test/with.rb
|
129
135
|
homepage: https://github.com/soveran/cuba
|
130
136
|
licenses:
|
131
137
|
- MIT
|
@@ -146,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
152
|
version: '0'
|
147
153
|
requirements: []
|
148
154
|
rubyforge_project:
|
149
|
-
rubygems_version: 2.0.
|
155
|
+
rubygems_version: 2.0.14
|
150
156
|
signing_key:
|
151
157
|
specification_version: 4
|
152
158
|
summary: Microframework for web applications.
|