cuba 3.3.0 → 3.4.0
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/.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.
|