roda 3.83.0 → 3.84.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/lib/roda/plugins/hsts.rb +35 -0
- data/lib/roda/response.rb +1 -1
- data/lib/roda/version.rb +1 -1
- metadata +4 -179
- data/CHANGELOG +0 -691
- data/README.rdoc +0 -1136
- data/doc/conventions.rdoc +0 -177
- data/doc/release_notes/3.0.0.txt +0 -84
- data/doc/release_notes/3.1.0.txt +0 -24
- data/doc/release_notes/3.10.0.txt +0 -132
- data/doc/release_notes/3.11.0.txt +0 -54
- data/doc/release_notes/3.12.0.txt +0 -19
- data/doc/release_notes/3.13.0.txt +0 -38
- data/doc/release_notes/3.14.0.txt +0 -36
- data/doc/release_notes/3.14.1.txt +0 -43
- data/doc/release_notes/3.15.0.txt +0 -21
- data/doc/release_notes/3.16.0.txt +0 -52
- data/doc/release_notes/3.17.0.txt +0 -62
- data/doc/release_notes/3.18.0.txt +0 -170
- data/doc/release_notes/3.19.0.txt +0 -229
- data/doc/release_notes/3.2.0.txt +0 -22
- data/doc/release_notes/3.20.0.txt +0 -7
- data/doc/release_notes/3.21.0.txt +0 -5
- data/doc/release_notes/3.22.0.txt +0 -24
- data/doc/release_notes/3.23.0.txt +0 -28
- data/doc/release_notes/3.24.0.txt +0 -14
- data/doc/release_notes/3.25.0.txt +0 -12
- data/doc/release_notes/3.26.0.txt +0 -15
- data/doc/release_notes/3.27.0.txt +0 -15
- data/doc/release_notes/3.28.0.txt +0 -13
- data/doc/release_notes/3.29.0.txt +0 -15
- data/doc/release_notes/3.3.0.txt +0 -291
- data/doc/release_notes/3.30.0.txt +0 -14
- data/doc/release_notes/3.31.0.txt +0 -11
- data/doc/release_notes/3.32.0.txt +0 -42
- data/doc/release_notes/3.33.0.txt +0 -8
- data/doc/release_notes/3.34.0.txt +0 -17
- data/doc/release_notes/3.35.0.txt +0 -12
- data/doc/release_notes/3.36.0.txt +0 -17
- data/doc/release_notes/3.37.0.txt +0 -42
- data/doc/release_notes/3.38.0.txt +0 -5
- data/doc/release_notes/3.39.0.txt +0 -16
- data/doc/release_notes/3.4.0.txt +0 -24
- data/doc/release_notes/3.40.0.txt +0 -24
- data/doc/release_notes/3.41.0.txt +0 -9
- data/doc/release_notes/3.42.0.txt +0 -21
- data/doc/release_notes/3.43.0.txt +0 -34
- data/doc/release_notes/3.44.0.txt +0 -23
- data/doc/release_notes/3.45.0.txt +0 -22
- data/doc/release_notes/3.46.0.txt +0 -19
- data/doc/release_notes/3.47.0.txt +0 -13
- data/doc/release_notes/3.48.0.txt +0 -10
- data/doc/release_notes/3.49.0.txt +0 -18
- data/doc/release_notes/3.5.0.txt +0 -31
- data/doc/release_notes/3.50.0.txt +0 -21
- data/doc/release_notes/3.51.0.txt +0 -20
- data/doc/release_notes/3.52.0.txt +0 -20
- data/doc/release_notes/3.53.0.txt +0 -14
- data/doc/release_notes/3.54.0.txt +0 -48
- data/doc/release_notes/3.55.0.txt +0 -12
- data/doc/release_notes/3.56.0.txt +0 -33
- data/doc/release_notes/3.57.0.txt +0 -34
- data/doc/release_notes/3.58.0.txt +0 -16
- data/doc/release_notes/3.59.0.txt +0 -17
- data/doc/release_notes/3.6.0.txt +0 -21
- data/doc/release_notes/3.60.0.txt +0 -56
- data/doc/release_notes/3.61.0.txt +0 -24
- data/doc/release_notes/3.62.0.txt +0 -41
- data/doc/release_notes/3.63.0.txt +0 -36
- data/doc/release_notes/3.64.0.txt +0 -26
- data/doc/release_notes/3.65.0.txt +0 -12
- data/doc/release_notes/3.66.0.txt +0 -23
- data/doc/release_notes/3.67.0.txt +0 -25
- data/doc/release_notes/3.68.0.txt +0 -21
- data/doc/release_notes/3.69.0.txt +0 -33
- data/doc/release_notes/3.7.0.txt +0 -123
- data/doc/release_notes/3.70.0.txt +0 -19
- data/doc/release_notes/3.71.0.txt +0 -33
- data/doc/release_notes/3.72.0.txt +0 -48
- data/doc/release_notes/3.73.0.txt +0 -33
- data/doc/release_notes/3.74.0.txt +0 -28
- data/doc/release_notes/3.75.0.txt +0 -19
- data/doc/release_notes/3.76.0.txt +0 -18
- data/doc/release_notes/3.77.0.txt +0 -8
- data/doc/release_notes/3.78.0.txt +0 -99
- data/doc/release_notes/3.79.0.txt +0 -148
- data/doc/release_notes/3.8.0.txt +0 -27
- data/doc/release_notes/3.80.0.txt +0 -31
- data/doc/release_notes/3.81.0.txt +0 -24
- data/doc/release_notes/3.82.0.txt +0 -43
- data/doc/release_notes/3.83.0.txt +0 -6
- data/doc/release_notes/3.9.0.txt +0 -67
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
= New Feature
|
|
2
|
-
|
|
3
|
-
* The symbol_matcher method in the symbol_matchers plugin now
|
|
4
|
-
supports a block to allow for type conversion of matched
|
|
5
|
-
segments:
|
|
6
|
-
|
|
7
|
-
symbol_matcher(:date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d|
|
|
8
|
-
[Date.new(y.to_i, m.to_i, d.to_i)]
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
route do |r|
|
|
12
|
-
r.on :date do |date|
|
|
13
|
-
# date is an instance of Date
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
As shown above, the block should return an array of objects to yield
|
|
18
|
-
to the match block.
|
|
19
|
-
|
|
20
|
-
If you have a segment match the passed regexp, but decide during block
|
|
21
|
-
processing that you do not want to treat it as a match, you can have the
|
|
22
|
-
block return nil or false. This is useful if you want to make sure you
|
|
23
|
-
are using valid data:
|
|
24
|
-
|
|
25
|
-
symbol_matcher(:date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d|
|
|
26
|
-
y = y.to_i
|
|
27
|
-
m = m.to_i
|
|
28
|
-
d = d.to_i
|
|
29
|
-
[Date.new(y, m, d)] if Date.valid_date?(y, m, d)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
When providing a block when using the symbol_matchers method, that
|
|
33
|
-
symbol may not work with the params_capturing plugin.
|
data/doc/release_notes/3.7.0.txt
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* A content_security_policy plugin has been added for setting up an
|
|
4
|
-
appropriate Content-Security-Policy header. To configure the
|
|
5
|
-
default policy, load the plugin with a block:
|
|
6
|
-
|
|
7
|
-
plugin :content_security_policy do |csp|
|
|
8
|
-
csp.default_src :none
|
|
9
|
-
csp.img_src :self
|
|
10
|
-
csp.style_src :self, 'fonts.googleapis.com'
|
|
11
|
-
csp.script_src :self
|
|
12
|
-
csp.font_src :self, 'fonts.gstatic.com'
|
|
13
|
-
csp.form_action :self
|
|
14
|
-
csp.base_uri :none
|
|
15
|
-
csp.frame_ancestors :none
|
|
16
|
-
csp.block_all_mixed_content
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
It's recommended that use use a default_src of :none at the top
|
|
20
|
-
of the policy, then explicitly change other settings (e.g. img_src)
|
|
21
|
-
when you want to allow content.
|
|
22
|
-
|
|
23
|
-
Anywhere in the routing tree, you can use the content_security_policy
|
|
24
|
-
method to override the default policy. You can pass this method a
|
|
25
|
-
block:
|
|
26
|
-
|
|
27
|
-
r.get 'foo' do
|
|
28
|
-
content_security_policy do |csp|
|
|
29
|
-
csp.object_src :self
|
|
30
|
-
csp.add_style_src 'bar.com'
|
|
31
|
-
end
|
|
32
|
-
# ...
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
Or just call a method on it:
|
|
36
|
-
|
|
37
|
-
r.get 'foo' do
|
|
38
|
-
content_security_policy.script_src :self, 'example.com', [:nonce, 'foobarbaz']
|
|
39
|
-
# ...
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
The following methods exist for configuring the content security policy, they set
|
|
43
|
-
the appropriate directive, with the underscores replaced by a dash.
|
|
44
|
-
|
|
45
|
-
* base_uri
|
|
46
|
-
* child_src
|
|
47
|
-
* connect_src
|
|
48
|
-
* default_src
|
|
49
|
-
* font_src
|
|
50
|
-
* form_action
|
|
51
|
-
* frame_ancestors
|
|
52
|
-
* frame_src
|
|
53
|
-
* img_src
|
|
54
|
-
* manifest_src
|
|
55
|
-
* media_src
|
|
56
|
-
* object_src
|
|
57
|
-
* plugin_types
|
|
58
|
-
* report_uri
|
|
59
|
-
* require_sri_for
|
|
60
|
-
* sandbox
|
|
61
|
-
* script_src
|
|
62
|
-
* style_src
|
|
63
|
-
* worker_src
|
|
64
|
-
|
|
65
|
-
All of these methods support any number of arguments, and each argument
|
|
66
|
-
should be one of the following types:
|
|
67
|
-
|
|
68
|
-
String :: used verbatim
|
|
69
|
-
Symbol :: Substitutes underscore with dash and surrounds with single
|
|
70
|
-
quotes
|
|
71
|
-
Array :: only accepts 2 element arrays, joins elements with a dash
|
|
72
|
-
and surrounds them with single quotes
|
|
73
|
-
|
|
74
|
-
Example:
|
|
75
|
-
|
|
76
|
-
content_security_policy.script_src :self, :unsafe_eval,
|
|
77
|
-
'example.com', [:nonce, 'foobarbaz']
|
|
78
|
-
# script-src 'self' 'unsafe-eval' example.com 'nonce-foobarbaz';
|
|
79
|
-
|
|
80
|
-
When calling a method with no arguments, the setting is removed from
|
|
81
|
-
the policy instead of being left empty, since all of these setting
|
|
82
|
-
require at least one value. Likewise, if the policy does not have
|
|
83
|
-
any settings, the header will not be added.
|
|
84
|
-
|
|
85
|
-
Calling the method overrides any previous setting. Each of the
|
|
86
|
-
methods has a add_* method (e.g. add_script_src) for appending to the
|
|
87
|
-
current setting, and a get_* method (e.g. get_script_src) for
|
|
88
|
-
retrieving the current value of the setting, or nil if it is not
|
|
89
|
-
defined.
|
|
90
|
-
|
|
91
|
-
content_security_policy.script_src :self, :unsafe_eval
|
|
92
|
-
# script-src 'self' 'unsafe-eval';
|
|
93
|
-
content_security_policy.add_script_src 'example.com', [:nonce, 'foobarbaz']
|
|
94
|
-
# script-src 'self' 'unsafe-eval' example.com 'nonce-foobarbaz';
|
|
95
|
-
|
|
96
|
-
content_security_policy.get_script_src 'example.com', [:nonce, 'foobarbaz']
|
|
97
|
-
# => [:self, :unsafe_eval, 'example.com', [:nonce, 'foobarbaz']]
|
|
98
|
-
|
|
99
|
-
The clear method can be used to remove all settings from the policy.
|
|
100
|
-
|
|
101
|
-
The following methods to set boolean directives are also defined:
|
|
102
|
-
|
|
103
|
-
* block_all_mixed_content
|
|
104
|
-
* upgrade_insecure_requests
|
|
105
|
-
|
|
106
|
-
Calling these methods will turn on the related setting. To turn the
|
|
107
|
-
setting off again, you can call them with a false argument (e.g.
|
|
108
|
-
block_all_mixed_content(false)). Each method also an *? method
|
|
109
|
-
(e.g. block_all_mixed_content?) for returning whether the setting is
|
|
110
|
-
currently enabled.
|
|
111
|
-
|
|
112
|
-
Likewise there is also a report_only method for turning on report
|
|
113
|
-
only mode (the default is enforcement mode), or turning off report
|
|
114
|
-
only mode if a false argument is given. Also, there is a
|
|
115
|
-
report_only? method for returning whether report only mode is
|
|
116
|
-
enabled. In report only mode, the Content-Security-Policy-Report-Only
|
|
117
|
-
header is used.
|
|
118
|
-
|
|
119
|
-
= Other Improvements
|
|
120
|
-
|
|
121
|
-
* The response_request plugin now integrates with the error_handler and
|
|
122
|
-
class_level_routing plugins. Those plugins now reinitialize the
|
|
123
|
-
current response object instead of creating a new response object.
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* A plain_hash_response_headers plugin has been added. On Rack 3,
|
|
4
|
-
this changes Roda to use a plain hash for response headers (as it
|
|
5
|
-
does on Rack 2), instead of using Rack::Headers (the default on
|
|
6
|
-
Rack 3). For a minimal app, using this plugin can almost double
|
|
7
|
-
the performance on Rack 3. Before using this plugin, you should
|
|
8
|
-
make sure that all response headers set explictly in your
|
|
9
|
-
application are already lower-case.
|
|
10
|
-
|
|
11
|
-
= Improvements
|
|
12
|
-
|
|
13
|
-
* Roda now natively uses lower-case for all response headers set
|
|
14
|
-
implicitly when using Rack 3. Previously, Roda used mixed-case
|
|
15
|
-
response headers and had Rack::Headers handle the conversion to
|
|
16
|
-
lower-case (Rack 3 requires lower-case response headers). Note
|
|
17
|
-
that Rack::Headers is still used for response headers by default
|
|
18
|
-
on Rack 3, as applications may not have converted to using
|
|
19
|
-
lower-case response headers.
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
= New Feature
|
|
2
|
-
|
|
3
|
-
* A match_hook_args plugin has been added. This is similar to the
|
|
4
|
-
existing match_hook plugin, but passes through the matchers and
|
|
5
|
-
block arguments (values yielded to the match block). Example:
|
|
6
|
-
|
|
7
|
-
plugin :match_hook_args
|
|
8
|
-
|
|
9
|
-
add_match_hook do |matchers, block_args|
|
|
10
|
-
logger.debug("matchers: #{matchers.inspect}. #{block_args.inspect} yielded.")
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# Term is an implicit matcher used for terminating matches, and
|
|
14
|
-
# will be included in the array of matchers yielded to the match hook
|
|
15
|
-
# if a terminating match is used.
|
|
16
|
-
term = self.class::RodaRequest::TERM
|
|
17
|
-
|
|
18
|
-
route do |r|
|
|
19
|
-
r.root do
|
|
20
|
-
# for a request for /
|
|
21
|
-
# matchers: nil, block_args: nil
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
r.on 'a', ['b', 'c'], Integer do |segment, id|
|
|
25
|
-
# for a request for /a/b/1
|
|
26
|
-
# matchers: ["a", ["b", "c"], Integer], block_args: ["b", 1]
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
r.get 'd' do
|
|
30
|
-
# for a request for /d
|
|
31
|
-
# matchers: ["d", term], block_args: []
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* An invalid_request_body plugin has been added for allowing custom
|
|
4
|
-
handling of invalid request bodies. Roda uses Rack's request body
|
|
5
|
-
parsing, and by default invalid request bodies can result in
|
|
6
|
-
different exceptions based on how the body is invalid and which
|
|
7
|
-
version of Rack is in use.
|
|
8
|
-
|
|
9
|
-
If you want to treat an invalid request body as the submission of
|
|
10
|
-
no parameters, you can use the :empty_hash argument when loading
|
|
11
|
-
the plugin:
|
|
12
|
-
|
|
13
|
-
plugin :invalid_request_body, :empty_hash
|
|
14
|
-
|
|
15
|
-
If you want to return a empty 400 (Bad Request) response if an
|
|
16
|
-
invalid request body is submitted, you can use the :empty_400
|
|
17
|
-
argument when loading the plugin:
|
|
18
|
-
|
|
19
|
-
plugin :invalid_request_body, :empty_400
|
|
20
|
-
|
|
21
|
-
If you want to raise a Roda::RodaPlugins::InvalidRequestBody::Error
|
|
22
|
-
exception if an invalid request body is submitted (which makes it
|
|
23
|
-
easier to handle these exceptions when using the error_handler
|
|
24
|
-
plugin), you can use the :raise argument when loading the plugin:
|
|
25
|
-
|
|
26
|
-
plugin :invalid_request_body, :raise
|
|
27
|
-
|
|
28
|
-
For custom behavior, you can pass a block when loading the plugin
|
|
29
|
-
The block is called with the exception Rack raised when parsing the
|
|
30
|
-
body. The block will be used to define a method in the application's
|
|
31
|
-
RodaRequest class. It can either return a hash of parameters, or
|
|
32
|
-
you can raise a different exception, or you can halt processing and
|
|
33
|
-
return a response:
|
|
34
|
-
|
|
35
|
-
plugin :invalid_request_body do |exception|
|
|
36
|
-
# To treat the exception raised as a submitted parameter
|
|
37
|
-
{body_error: exception}
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
= Other Improvements
|
|
41
|
-
|
|
42
|
-
* When using the check_arity: :warn Roda option, Roda now correctly
|
|
43
|
-
warns when defining a method that expects a single argument when
|
|
44
|
-
the provided block requires multiple arguments.
|
|
45
|
-
|
|
46
|
-
* The match_hooks plugin is now implemented using the match_hook_args
|
|
47
|
-
plugin, simplifying the implementation. This change should be
|
|
48
|
-
transparent unless you were reaching into the internals.
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* The middleware plugin now accepts a :next_if_not_found option.
|
|
4
|
-
This allows the middleware plugin to pass the request to the next
|
|
5
|
-
application if the current application handles the request but
|
|
6
|
-
ends up calling the not_found handler. With the following
|
|
7
|
-
middleware:
|
|
8
|
-
|
|
9
|
-
class Mid < Roda
|
|
10
|
-
plugin :middleware
|
|
11
|
-
|
|
12
|
-
route do |r|
|
|
13
|
-
r.on "foo" do
|
|
14
|
-
r.get "bar" do
|
|
15
|
-
'bar'
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
Requests for /x would be forwarded to the next application, since
|
|
22
|
-
the application doesn't handle the request, but requests for /foo/x
|
|
23
|
-
would not be, because the middleware is partially handling the
|
|
24
|
-
request in the r.on "foo" block. With the :next_if_not_found
|
|
25
|
-
option, only requests for /foo/bar would be handled by the
|
|
26
|
-
middleware, and all other requests would be forwarded to the next
|
|
27
|
-
application.
|
|
28
|
-
|
|
29
|
-
= Other Improvements
|
|
30
|
-
|
|
31
|
-
* The sessions and route_csrf plugins no longer depend on the base64
|
|
32
|
-
library. base64 will be removed from Ruby's standard library
|
|
33
|
-
starting in Ruby 3.4.
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* A redirect_http_to_https plugin has been added, redirecting HTTP
|
|
4
|
-
requests to the same path on an HTTPS site. Using the routing tree,
|
|
5
|
-
you can control where to do the redirection, which allows you to
|
|
6
|
-
easily have part of your site accessible via HTTP, with sensitive
|
|
7
|
-
sections requiring HTTPS:
|
|
8
|
-
|
|
9
|
-
plugin :redirect_http_to_https
|
|
10
|
-
|
|
11
|
-
route do |r|
|
|
12
|
-
# routes available via both HTTP and HTTPS
|
|
13
|
-
r.redirect_http_to_https
|
|
14
|
-
# routes available only via HTTPS
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
If you want to redirect to HTTPS for all routes in the routing tree, you
|
|
18
|
-
can have r.redirect_http_to_https as the very first method call in the
|
|
19
|
-
routing tree. Note that in Roda it is possible to handle routing before
|
|
20
|
-
the normal routing tree using before hooks. The static_routing and
|
|
21
|
-
heartbeat plugins use this feature. If you would like to handle routes
|
|
22
|
-
before the normal routing tree, you can setup a before hook:
|
|
23
|
-
|
|
24
|
-
plugin :hooks
|
|
25
|
-
|
|
26
|
-
before do
|
|
27
|
-
request.redirect_http_to_https
|
|
28
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* A cookie_flags plugin has been added, for overriding, warning, or
|
|
4
|
-
raising for incorrect cookie flags. The plugin by default checks
|
|
5
|
-
whether the secure, httponly, and samesite=strict flags are set.
|
|
6
|
-
The default behavior is to add the appropriate flags if they are
|
|
7
|
-
not set, and change the samesite flag to strict if it is set to
|
|
8
|
-
something else. You can configure the flag checking behavior
|
|
9
|
-
via the :httponly, :same_site, and :secure options.
|
|
10
|
-
|
|
11
|
-
You can configure the action the plugin takes via the :action option.
|
|
12
|
-
The default action is to modify the flags, but the :action option can
|
|
13
|
-
be set to :raise, :warn, or :warn_and_modify to override the behavior.
|
|
14
|
-
|
|
15
|
-
The recommended way to use the plugin is to use it during testing,
|
|
16
|
-
and specify action: :raise, so you can catch places where cookies
|
|
17
|
-
are set with the wrong flags. Then you can fix those places to
|
|
18
|
-
use the correct flags, which is better than relying on the plugin
|
|
19
|
-
at runtime in production to fix incorrect flags.
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* A break plugin has been added, allowing you to use break from
|
|
4
|
-
inside a routing block and continue routing after the block. This
|
|
5
|
-
offers the same feature as the pass plugin, but using the standard
|
|
6
|
-
break keyword instead of the r.pass method.
|
|
7
|
-
|
|
8
|
-
* The error_mail and error_email features now both accept a :filter
|
|
9
|
-
plugin option. The value should respond to call with two arguments.
|
|
10
|
-
The first arguments is the key, and the second is the value, and
|
|
11
|
-
should return a truthy value if the value should be filtered. This
|
|
12
|
-
will be used for filtering parameter values, ENV values, and session
|
|
13
|
-
values in the generated emails.
|
|
14
|
-
|
|
15
|
-
= Other Improvements
|
|
16
|
-
|
|
17
|
-
* On Ruby 3.3+, the middleware plugin sets a temporary class name for
|
|
18
|
-
the created middleware, based on the class name of the Roda app.
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* The route_csrf plugin now supports formaction/formmethod attributes
|
|
4
|
-
in forms. A csrf_formaction_tag method has been added for creating
|
|
5
|
-
a hidden input for a particular path and method. When a form is
|
|
6
|
-
submitted, the check_csrf! method will fix check for a path-specific
|
|
7
|
-
csrf token (set by the hidden tag added by the csrf_formaction_tag
|
|
8
|
-
method), before checking for the default csrf token.
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* A permissions_policy plugin has been added that allows you to easily set a
|
|
4
|
-
Permissions-Policy header for the application, which browsers can use to
|
|
5
|
-
determine whether to allow specific functionality on the returned page
|
|
6
|
-
(mainly related to which JavaScript APIs the page is allowed to use).
|
|
7
|
-
|
|
8
|
-
You would generally call the plugin with a block to set the default policy:
|
|
9
|
-
|
|
10
|
-
plugin :permissions_policy do |pp|
|
|
11
|
-
pp.camera :none
|
|
12
|
-
pp.fullscreen :self
|
|
13
|
-
pp.clipboard_read :self, 'https://example.com'
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
Then, anywhere in the routing tree, you can customize the policy for just that
|
|
17
|
-
branch or action using the same block syntax:
|
|
18
|
-
|
|
19
|
-
r.get 'foo' do
|
|
20
|
-
permissions_policy do |pp|
|
|
21
|
-
pp.camera :self
|
|
22
|
-
end
|
|
23
|
-
# ...
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
In addition to using a block, you can also call methods on the object returned
|
|
27
|
-
by the method:
|
|
28
|
-
|
|
29
|
-
r.get 'foo' do
|
|
30
|
-
permissions_policy.camera :self
|
|
31
|
-
# ...
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
You can use the :default plugin option to set the default for all settings.
|
|
35
|
-
For example, to disallow all access for each setting by default:
|
|
36
|
-
|
|
37
|
-
plugin :permissions_policy, default: :none
|
|
38
|
-
|
|
39
|
-
The following methods are available for configuring the permissions policy,
|
|
40
|
-
which specify the setting (substituting _ with -):
|
|
41
|
-
|
|
42
|
-
* accelerometer
|
|
43
|
-
* ambient_light_sensor
|
|
44
|
-
* autoplay
|
|
45
|
-
* bluetooth
|
|
46
|
-
* camera
|
|
47
|
-
* clipboard_read
|
|
48
|
-
* clipboard_write
|
|
49
|
-
* display_capture
|
|
50
|
-
* encrypted_media
|
|
51
|
-
* fullscreen
|
|
52
|
-
* geolocation
|
|
53
|
-
* gyroscope
|
|
54
|
-
* hid
|
|
55
|
-
* idle_detection
|
|
56
|
-
* keyboard_map
|
|
57
|
-
* magnetometer
|
|
58
|
-
* microphone
|
|
59
|
-
* midi
|
|
60
|
-
* payment
|
|
61
|
-
* picture_in_picture
|
|
62
|
-
* publickey_credentials_get
|
|
63
|
-
* screen_wake_lock
|
|
64
|
-
* serial
|
|
65
|
-
* sync_xhr
|
|
66
|
-
* usb
|
|
67
|
-
* web_share
|
|
68
|
-
* window_management
|
|
69
|
-
|
|
70
|
-
All of these methods support any number of arguments, and each argument should
|
|
71
|
-
be one of the following values:
|
|
72
|
-
|
|
73
|
-
:all :: Grants permission to all domains (must be only argument)
|
|
74
|
-
:none :: Does not allow permission at all (must be only argument)
|
|
75
|
-
:self :: Allows feature in current document and any nested browsing contexts
|
|
76
|
-
that use the same domain as the current document.
|
|
77
|
-
:src :: Allows feature in current document and any nested browsing contexts
|
|
78
|
-
that use the same domain as the src of the iframe.
|
|
79
|
-
String :: Specifies origin domain where access is allowed
|
|
80
|
-
|
|
81
|
-
When calling a method with no arguments, the setting is removed from the policy instead
|
|
82
|
-
of being left empty, since all of these setting require at least one value. Likewise,
|
|
83
|
-
if the policy does not have any settings, the header will not be added.
|
|
84
|
-
|
|
85
|
-
Calling the method overrides any previous setting. Each of the methods has +add_*+ and
|
|
86
|
-
+get_*+ methods defined. The +add_*+ method appends to any existing setting, and the +get_*+ method
|
|
87
|
-
returns the current value for the setting (this will be +:all+ if all domains are allowed, or
|
|
88
|
-
any array of strings/:self/:src).
|
|
89
|
-
|
|
90
|
-
permissions_policy.fullscreen :self, 'https://example.com'
|
|
91
|
-
# fullscreen (self "https://example.com")
|
|
92
|
-
|
|
93
|
-
permissions_policy.add_fullscreen 'https://*.example.com'
|
|
94
|
-
# fullscreen (self "https://example.com" "https://*.example.com")
|
|
95
|
-
|
|
96
|
-
permissions_policy.get_fullscreen
|
|
97
|
-
# => [:self, "https://example.com", "https://*.example.com"]
|
|
98
|
-
|
|
99
|
-
The clear method can be used to remove all settings from the policy.
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* The hmac_paths plugin allows protection of paths using an HMAC. This can be used
|
|
4
|
-
to prevent users enumerating paths, since only paths with valid HMACs will be
|
|
5
|
-
respected.
|
|
6
|
-
|
|
7
|
-
To use the plugin, you must provide a :secret option. This sets the secret for
|
|
8
|
-
the HMACs. Make sure to keep this value secret, as this plugin does not provide
|
|
9
|
-
protection against users who know the secret value. The secret must be at least
|
|
10
|
-
32 bytes.
|
|
11
|
-
|
|
12
|
-
plugin :hmac_paths, secret: 'some-secret-value-with-at-least-32-bytes'
|
|
13
|
-
|
|
14
|
-
To generate a valid HMAC path, you call the hmac_path method:
|
|
15
|
-
|
|
16
|
-
hmac_path('/widget/1')
|
|
17
|
-
# => "/0c2feaefdfc80cc73da19b060c713d4193c57022815238c6657ce2d99b5925eb/0/widget/1"
|
|
18
|
-
|
|
19
|
-
The first segment in the returned path is the HMAC. The second segment is flags for
|
|
20
|
-
the type of paths (see below), and the rest of the path is as given.
|
|
21
|
-
|
|
22
|
-
To protect a path or any subsection in the routing tree, you wrap the related code
|
|
23
|
-
in an +r.hmac_path+ block.
|
|
24
|
-
|
|
25
|
-
route do |r|
|
|
26
|
-
r.hmac_path do
|
|
27
|
-
r.get 'widget', Integer do |widget_id|
|
|
28
|
-
# ...
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
If first segment of the remaining path contains a valid HMAC for the rest of the path (considering
|
|
34
|
-
the flags), then r.hmac_path will match and yield to the block, and routing continues inside
|
|
35
|
-
the block with the HMAC and flags segments removed.
|
|
36
|
-
|
|
37
|
-
In the above example, if you provide a user a link for widget with ID 1, there is no way
|
|
38
|
-
for them to guess the valid path for the widget with ID 2, preventing a user from
|
|
39
|
-
enumerating widgets, without relying on custom access control. Users can only access
|
|
40
|
-
paths that have been generated by the application and provided to them, either directly
|
|
41
|
-
or indirectly.
|
|
42
|
-
|
|
43
|
-
In the above example, r.hmac_path is used at the root of the routing tree. If you
|
|
44
|
-
would like to call it below the root of the routing tree, it works correctly, but you
|
|
45
|
-
must pass hmac_path the :root option specifying where r.hmac_paths will be called from.
|
|
46
|
-
Consider this example:
|
|
47
|
-
|
|
48
|
-
route do |r|
|
|
49
|
-
r.on 'widget' do
|
|
50
|
-
r.hmac_path do
|
|
51
|
-
r.get Integer do |widget_id|
|
|
52
|
-
# ...
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
r.on 'foobar' do
|
|
58
|
-
r.hmac_path do
|
|
59
|
-
r.get Integer do |foobar_id|
|
|
60
|
-
# ...
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
For security reasons, the hmac_path plugin does not allow an HMAC path designed for
|
|
67
|
-
widgets to be a valid match in the r.hmac_path call inside the "r.on 'foobar'"
|
|
68
|
-
block, preventing users who have a valid HMAC for a widget from looking at the page for
|
|
69
|
-
a foobar with the same ID. When generating HMAC paths where the matching r.hmac_path
|
|
70
|
-
call is not at the root of the routing tree, you must pass the :root option:
|
|
71
|
-
|
|
72
|
-
hmac_path('/1', root: '/widget')
|
|
73
|
-
# => "/widget/daccafce3ce0df52e5ce774626779eaa7286085fcbde1e4681c74175ff0bbacd/0/1"
|
|
74
|
-
|
|
75
|
-
hmac_path('/1', root: '/foobar')
|
|
76
|
-
# => "/foobar/c5fdaf482771d4f9f38cc13a1b2832929026a4ceb05e98ed6a0cd5a00bf180b7/0/1"
|
|
77
|
-
|
|
78
|
-
Note how the HMAC changes even though the path is the same.
|
|
79
|
-
|
|
80
|
-
In addition to the +:root+ option, there are additional options that further constrain
|
|
81
|
-
use of the generated paths.
|
|
82
|
-
|
|
83
|
-
The :method option creates a path that can only be called with a certain request
|
|
84
|
-
method:
|
|
85
|
-
|
|
86
|
-
hmac_path('/widget/1', method: :get)
|
|
87
|
-
# => "/d38c1e634ecf9a3c0ab9d0832555b035d91b35069efcbf2670b0dfefd4b62fdd/m/widget/1"
|
|
88
|
-
|
|
89
|
-
Note how this results in a different HMAC than the original hmac_path('/widget/1')
|
|
90
|
-
call. This sets the flags segment to "m", which means r.hmac_path will consider the
|
|
91
|
-
request mehod when checking the HMAC, and will only match if the provided request method
|
|
92
|
-
is GET. This allows you to provide a user the ability to submit a GET request for the
|
|
93
|
-
underlying path, without providing them the ability to submit a POST request for the
|
|
94
|
-
underlying path, with no other access control.
|
|
95
|
-
|
|
96
|
-
The :params option accepts a hash of params, converts it into a query string, and
|
|
97
|
-
includes the query string in the returned path. It sets the flags segment to +p+, which
|
|
98
|
-
means r.hmac_path will check for that exact query string. Requests with an empty query
|
|
99
|
-
string or a different string will not match.
|
|
100
|
-
|
|
101
|
-
hmac_path('/widget/1', params: {foo: 'bar'})
|
|
102
|
-
# => "/fe8d03f9572d5af6c2866295bd3c12c2ea11d290b1cbd016c3b68ee36a678139/p/widget/1?foo=bar"
|
|
103
|
-
|
|
104
|
-
For GET requests, which cannot have request bodies, that is sufficient to ensure that the
|
|
105
|
-
submitted params are exactly as specified. However, POST requests can have request bodies,
|
|
106
|
-
and request body params override query string params in r.params. So if you are using
|
|
107
|
-
this for POST requests (or other HTTP verbs that can have request bodies), use r.GET
|
|
108
|
-
instead of r.params to specifically check query string parameters.
|
|
109
|
-
|
|
110
|
-
You can use +:root+, +:method+, and +:params+ at the same time:
|
|
111
|
-
|
|
112
|
-
hmac_path('/1', root: '/widget', method: :get, params: {foo: 'bar'})
|
|
113
|
-
# => "/widget/9169af1b8f40c62a1c2bb15b1b377c65bda681b8efded0e613a4176387468c15/mp/1?foo=bar"
|
|
114
|
-
|
|
115
|
-
This gives you a path only valid for a GET request with a root of "/widget" and
|
|
116
|
-
a query string of "foo=bar".
|
|
117
|
-
|
|
118
|
-
To handle secret rotation, you can provide an :old_secret option when loading the
|
|
119
|
-
plugin.
|
|
120
|
-
|
|
121
|
-
plugin :hmac_paths, secret: 'some-secret-value-with-at-least-32-bytes',
|
|
122
|
-
old_secret: 'previous-secret-value-with-at-least-32-bytes'
|
|
123
|
-
|
|
124
|
-
This will use :secret for constructing new paths, but will respect paths generated by
|
|
125
|
-
:old_secret.
|
|
126
|
-
|
|
127
|
-
= Other Improvements
|
|
128
|
-
|
|
129
|
-
* When not using cached templates in the render plugin, the render plugin
|
|
130
|
-
now has better handling when a template is modified and results in an
|
|
131
|
-
error. Previously, the error would be raised on the first request after
|
|
132
|
-
the template modification, but subsequent requests would use the
|
|
133
|
-
previous template value. The render plugin will no longer update the
|
|
134
|
-
last modified time in this case, so if a template is modified and
|
|
135
|
-
introduces an error (e.g. SyntaxError in an erb template), all future
|
|
136
|
-
requests that use the template will result in the error being raised,
|
|
137
|
-
until the template is fixed.
|
|
138
|
-
|
|
139
|
-
= Backwards Compatibility
|
|
140
|
-
|
|
141
|
-
* The internal TemplateMtimeWrapper API has been modified. As documented,
|
|
142
|
-
this is an internal class and the API can change in any Roda version.
|
|
143
|
-
However, if any code was relying on the previous implementation of
|
|
144
|
-
TemplateMtimeWrapper#modified?, it will need to be modified, as that
|
|
145
|
-
method has been replaced with TemplateMtimeWrapper#if_modified.
|
|
146
|
-
|
|
147
|
-
Additionally, the TemplateMtimeWrapper#compiled_method_lambda API has
|
|
148
|
-
also changed.
|
data/doc/release_notes/3.8.0.txt
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* The convert_each! method in the typecast_params plugin now
|
|
4
|
-
accepts a Proc or Method value for the :keys option. The proc
|
|
5
|
-
or method is called with the current array or hash that
|
|
6
|
-
typecast params is operating on, and should return an
|
|
7
|
-
array of keys to use for the conversion.
|
|
8
|
-
|
|
9
|
-
* The convert_each! method in the typecast_params plugin will
|
|
10
|
-
now automatically handle hashes with keys from '0'..'N',
|
|
11
|
-
without a :keys option being provided.
|
|
12
|
-
|
|
13
|
-
This makes it possible to handle parameter names such as
|
|
14
|
-
foo[0][bar], foo[0][baz], foo[1][bar], and foo[1][baz], if you
|
|
15
|
-
want to avoid the issues related to rack's issues when parsing
|
|
16
|
-
array parameters.
|
|
17
|
-
|
|
18
|
-
= Other Improvements
|
|
19
|
-
|
|
20
|
-
* The Roda::RodaVersionNumber constant has been added for easier
|
|
21
|
-
version comparisons. It is 30080 for version 3.8.0.
|
|
22
|
-
|
|
23
|
-
= Backwards Compatibility
|
|
24
|
-
|
|
25
|
-
* When an unsupported type is given as value of the :keys option
|
|
26
|
-
to the convert_each! method in the typecast_params plugin, a
|
|
27
|
-
ProgrammerError exception is now raised.
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
= New Features
|
|
2
|
-
|
|
3
|
-
* The hmac_paths plugin now supports a :namespace option for both hmac_path and
|
|
4
|
-
r.hmac_path. The :namespace option makes the generated HMAC values unique
|
|
5
|
-
per namespace, allowing easy use of per user/group HMAC paths. This can
|
|
6
|
-
be useful if the same path will show different information to different
|
|
7
|
-
users/groups, and you want to prevent path enumeration for each user/group
|
|
8
|
-
(not allow paths enumerated by one user/group to be valid for a different
|
|
9
|
-
user/group). Example:
|
|
10
|
-
|
|
11
|
-
hmac_path('/widget/1', namespace: '1')
|
|
12
|
-
# => "/3793ac2a72ea399c40cbd63f154d19f0fe34cdf8d347772134c506a0b756d590/n/widget/1"
|
|
13
|
-
|
|
14
|
-
hmac_path('/widget/1', namespace: '2')
|
|
15
|
-
# => "/0e1e748860d4fd17fe9b7c8259b1e26996502c38e465f802c2c9a0a13000087c/n/widget/1"
|
|
16
|
-
|
|
17
|
-
The HMAC path created with namespace: '1' will only be valid when calling
|
|
18
|
-
r.hmac_path with namespace: '1' (similar for namespace: '2').
|
|
19
|
-
|
|
20
|
-
It is expected that the most common use of the :namespace option is to
|
|
21
|
-
reference session values, so the value of each path depends on the logged in
|
|
22
|
-
user. You can use the :namespace_session_key plugin option to set the
|
|
23
|
-
default namespace for both hmac_path and r.hmac_path:
|
|
24
|
-
|
|
25
|
-
plugin :hmac_paths, secret: 'some-secret-value-with-at-least-32-bytes',
|
|
26
|
-
namespace_session_key: 'account_id'
|
|
27
|
-
|
|
28
|
-
This will use <tt>session['account_id']</tt> (converted to a string) as the namespace
|
|
29
|
-
for both hmac_path and r.hmac_path, unless a specific :namespace option is
|
|
30
|
-
given, making it simple to implement per user/group HMAC paths across an
|
|
31
|
-
application.
|