roda 3.75.0 → 3.77.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/CHANGELOG +12 -0
- data/doc/release_notes/3.76.0.txt +18 -0
- data/doc/release_notes/3.77.0.txt +8 -0
- data/lib/roda/plugins/break.rb +43 -0
- data/lib/roda/plugins/error_email.rb +10 -1
- data/lib/roda/plugins/error_mail.rb +13 -2
- data/lib/roda/plugins/middleware.rb +3 -0
- data/lib/roda/plugins/route_csrf.rb +21 -2
- data/lib/roda/version.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8afa46b8055c19e63e1efeebf444b422cd810701c759936d476797515630245d
|
4
|
+
data.tar.gz: 4e857447435707de1d586857126795e2a1191f685ca8893e99cd1c78aeb50c02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ecfeb211d574d46bdc31995c3551afb97af50acf8567cce83b46808e87ff797a5ef7c769e42c0477ed6a6d9271040b818da72e77c91e4f91f9760201d2cd5ca
|
7
|
+
data.tar.gz: 45e67fbd1da64839c6dc5a8dc0975a0dca5f67a77c83ae79a62ab22e7d9cf0002cb8b8f6a22661bdaf97ad973b6bc6ff928af2e416a96c35b12150e9fe0eaf4d
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
= 3.77.0 (2024-02-12)
|
2
|
+
|
3
|
+
* Support formaction/formmethod attributes in forms in route_csrf plugin (jeremyevans)
|
4
|
+
|
5
|
+
= 3.76.0 (2024-01-12)
|
6
|
+
|
7
|
+
* Support :filter plugin option in error_mail and error_email for filtering parameters, environment variables, and session values (jeremyevans) (#346)
|
8
|
+
|
9
|
+
* Set temporary name on Ruby 3.3 in middleware plugin for middleware class created (janko) (#344)
|
10
|
+
|
11
|
+
* Add break plugin, for using break inside a routing block to return from the block and keep routing (jeremyevans)
|
12
|
+
|
1
13
|
= 3.75.0 (2023-12-14)
|
2
14
|
|
3
15
|
* Add cookie_flags plugin, for overriding, warning, or raising for incorrect cookie flags (jeremyevans)
|
@@ -0,0 +1,18 @@
|
|
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.
|
@@ -0,0 +1,8 @@
|
|
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.
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The break plugin supports calling break inside a match block, to
|
7
|
+
# return from the block and continue in the routing tree, restoring
|
8
|
+
# the remaining path so that future matchers operating on the path
|
9
|
+
# operate as expected.
|
10
|
+
#
|
11
|
+
# plugin :break
|
12
|
+
#
|
13
|
+
# route do |r|
|
14
|
+
# r.on "foo", :bar do |bar|
|
15
|
+
# break if bar == 'baz'
|
16
|
+
# "/foo/#{bar} (not baz)"
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# r.on "foo/baz" do
|
20
|
+
# "/foo/baz"
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# This provides the same basic feature as the pass plugin, but
|
25
|
+
# uses Ruby's standard control flow primative instead of a
|
26
|
+
# separate method.
|
27
|
+
module Break
|
28
|
+
module RequestMethods
|
29
|
+
private
|
30
|
+
|
31
|
+
# Handle break inside match blocks, restoring remaining path.
|
32
|
+
def if_match(_)
|
33
|
+
rp = @remaining_path
|
34
|
+
super
|
35
|
+
ensure
|
36
|
+
@remaining_path = rp
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
register_plugin(:break, Break)
|
42
|
+
end
|
43
|
+
end
|
@@ -21,6 +21,9 @@ class Roda
|
|
21
21
|
#
|
22
22
|
# Options:
|
23
23
|
#
|
24
|
+
# :filter :: Callable called with the key and value for each parameter, environment
|
25
|
+
# variable, and session value. If it returns true, the value of the
|
26
|
+
# parameter is filtered in the email.
|
24
27
|
# :from :: The From address to use in the email (required)
|
25
28
|
# :headers :: A hash of additional headers to use in the email (default: empty hash)
|
26
29
|
# :host :: The SMTP server to use to send the email (default: localhost)
|
@@ -38,6 +41,7 @@ class Roda
|
|
38
41
|
# use an error reporting service instead of this plugin.
|
39
42
|
module ErrorEmail
|
40
43
|
DEFAULTS = {
|
44
|
+
:filter=>lambda{|k,v| false},
|
41
45
|
:headers=>OPTS,
|
42
46
|
:host=>'localhost',
|
43
47
|
# :nocov:
|
@@ -52,7 +56,12 @@ class Roda
|
|
52
56
|
{'From'=>h[:from], 'To'=>h[:to], 'Subject'=>"#{h[:prefix]}#{subject}"}
|
53
57
|
end,
|
54
58
|
:body=>lambda do |s, e|
|
55
|
-
|
59
|
+
filter = s.opts[:error_email][:filter]
|
60
|
+
format = lambda do |h|
|
61
|
+
h = h.map{|k, v| "#{k.inspect} => #{filter.call(k, v) ? 'FILTERED' : v.inspect}"}
|
62
|
+
h.sort!
|
63
|
+
h.join("\n")
|
64
|
+
end
|
56
65
|
|
57
66
|
begin
|
58
67
|
params = s.request.params
|
@@ -21,6 +21,9 @@ class Roda
|
|
21
21
|
#
|
22
22
|
# Options:
|
23
23
|
#
|
24
|
+
# :filter :: Callable called with the key and value for each parameter, environment
|
25
|
+
# variable, and session value. If it returns true, the value of the
|
26
|
+
# parameter is filtered in the email.
|
24
27
|
# :from :: The From address to use in the email (required)
|
25
28
|
# :headers :: A hash of additional headers to use in the email (default: empty hash)
|
26
29
|
# :prefix :: A prefix to use in the email's subject line (default: no prefix)
|
@@ -36,9 +39,12 @@ class Roda
|
|
36
39
|
# for low traffic web applications. For high traffic web applications,
|
37
40
|
# use an error reporting service instead of this plugin.
|
38
41
|
module ErrorMail
|
42
|
+
DEFAULT_FILTER = lambda{|k,v| false}
|
43
|
+
private_constant :DEFAULT_FILTER
|
44
|
+
|
39
45
|
# Set default opts for plugin. See ErrorEmail module RDoc for options.
|
40
46
|
def self.configure(app, opts=OPTS)
|
41
|
-
app.opts[:error_mail] = email_opts = (app.opts[:error_mail] ||
|
47
|
+
app.opts[:error_mail] = email_opts = (app.opts[:error_mail] || {:filter=>DEFAULT_FILTER}).merge(opts).freeze
|
42
48
|
unless email_opts[:to] && email_opts[:from]
|
43
49
|
raise RodaError, "must provide :to and :from options to error_mail plugin"
|
44
50
|
end
|
@@ -68,8 +74,13 @@ class Roda
|
|
68
74
|
e.to_s
|
69
75
|
end
|
70
76
|
subject = "#{email_opts[:prefix]}#{subject}"
|
77
|
+
filter = email_opts[:filter]
|
71
78
|
|
72
|
-
format = lambda
|
79
|
+
format = lambda do |h|
|
80
|
+
h = h.map{|k, v| "#{k.inspect} => #{filter.call(k, v) ? 'FILTERED' : v.inspect}"}
|
81
|
+
h.sort!
|
82
|
+
h.join("\n")
|
83
|
+
end
|
73
84
|
|
74
85
|
begin
|
75
86
|
params = request.params
|
@@ -134,6 +134,9 @@ class Roda
|
|
134
134
|
# and store +app+ as the next middleware to call.
|
135
135
|
def initialize(mid, app, *args, &block)
|
136
136
|
@mid = Class.new(mid)
|
137
|
+
# :nocov:
|
138
|
+
@mid.set_temporary_name("#{mid.name}(middleware)") if mid.name && RUBY_VERSION >= "3.3"
|
139
|
+
# :nocov:
|
137
140
|
if @mid.opts[:middleware_next_if_not_found]
|
138
141
|
@mid.plugin(:not_found, &NEXT_PROC)
|
139
142
|
end
|
@@ -42,6 +42,9 @@ class Roda
|
|
42
42
|
# This plugin supports the following options:
|
43
43
|
#
|
44
44
|
# :field :: Form input parameter name for CSRF token (default: '_csrf')
|
45
|
+
# :formaction_field :: Form input parameter name for path-specific CSRF tokens (used by the
|
46
|
+
# +csrf_formaction_tag+ method). If present, this parameter should be
|
47
|
+
# submitted as a hash, keyed by path, with CSRF token values.
|
45
48
|
# :header :: HTTP header name for CSRF token (default: 'X-CSRF-Token')
|
46
49
|
# :key :: Session key for CSRF secret (default: '_roda_csrf_secret')
|
47
50
|
# :require_request_specific_tokens :: Whether request-specific tokens are required (default: true).
|
@@ -86,6 +89,10 @@ class Roda
|
|
86
89
|
# override any of the plugin options for this specific call.
|
87
90
|
# The :token option can be used to specify the provided CSRF token
|
88
91
|
# (instead of looking for the token in the submitted parameters).
|
92
|
+
# csrf_formaction_tag(path, method='POST') :: An HTML hidden input tag string containing the CSRF token, suitable
|
93
|
+
# for placing in an HTML form that has inputs that use formaction
|
94
|
+
# attributes to change the endpoint to which the form is submitted.
|
95
|
+
# Takes the same arguments as csrf_token.
|
89
96
|
# csrf_field :: The field name to use for the hidden tag containing the CSRF token.
|
90
97
|
# csrf_path(action) :: This takes an argument that would be the value of the HTML form's
|
91
98
|
# action attribute, and returns a path you can pass to csrf_token
|
@@ -152,6 +159,7 @@ class Roda
|
|
152
159
|
# Default CSRF option values
|
153
160
|
DEFAULTS = {
|
154
161
|
:field => '_csrf'.freeze,
|
162
|
+
:formaction_field => '_csrfs'.freeze,
|
155
163
|
:header => 'X-CSRF-Token'.freeze,
|
156
164
|
:key => '_roda_csrf_secret'.freeze,
|
157
165
|
:require_request_specific_tokens => true,
|
@@ -252,6 +260,14 @@ class Roda
|
|
252
260
|
end
|
253
261
|
end
|
254
262
|
|
263
|
+
# An HTML hidden input tag string containing the CSRF token, used for inputs
|
264
|
+
# with formaction, so the same form can be used to submit to multiple endpoints
|
265
|
+
# depending on which button was clicked. See csrf_token for arguments, but the
|
266
|
+
# path argument is required.
|
267
|
+
def csrf_formaction_tag(path, *args)
|
268
|
+
"<input type=\"hidden\" name=\"#{csrf_options[:formaction_field]}[#{Rack::Utils.escape_html(path)}]\" value=\"#{csrf_token(path, *args)}\" \/>"
|
269
|
+
end
|
270
|
+
|
255
271
|
# An HTML hidden input tag string containing the CSRF token. See csrf_token for
|
256
272
|
# arguments.
|
257
273
|
def csrf_tag(*args)
|
@@ -291,6 +307,8 @@ class Roda
|
|
291
307
|
return
|
292
308
|
end
|
293
309
|
|
310
|
+
path = @_request.path
|
311
|
+
|
294
312
|
unless encoded_token = opts[:token]
|
295
313
|
encoded_token = case opts[:check_header]
|
296
314
|
when :only
|
@@ -298,7 +316,8 @@ class Roda
|
|
298
316
|
when true
|
299
317
|
return (csrf_invalid_message(opts.merge(:check_header=>false)) && csrf_invalid_message(opts.merge(:check_header=>:only)))
|
300
318
|
else
|
301
|
-
@_request.params
|
319
|
+
params = @_request.params
|
320
|
+
((formactions = params[opts[:formaction_field]]).is_a?(Hash) && (formactions[path])) || params[opts[:field]]
|
302
321
|
end
|
303
322
|
end
|
304
323
|
|
@@ -326,7 +345,7 @@ class Roda
|
|
326
345
|
|
327
346
|
random_data = submitted_hmac.slice!(0...31)
|
328
347
|
|
329
|
-
if csrf_compare(csrf_hmac(random_data, method,
|
348
|
+
if csrf_compare(csrf_hmac(random_data, method, path), submitted_hmac)
|
330
349
|
return
|
331
350
|
end
|
332
351
|
|
data/lib/roda/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.77.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -249,6 +249,8 @@ extra_rdoc_files:
|
|
249
249
|
- doc/release_notes/3.73.0.txt
|
250
250
|
- doc/release_notes/3.74.0.txt
|
251
251
|
- doc/release_notes/3.75.0.txt
|
252
|
+
- doc/release_notes/3.76.0.txt
|
253
|
+
- doc/release_notes/3.77.0.txt
|
252
254
|
- doc/release_notes/3.8.0.txt
|
253
255
|
- doc/release_notes/3.9.0.txt
|
254
256
|
files:
|
@@ -331,6 +333,8 @@ files:
|
|
331
333
|
- doc/release_notes/3.73.0.txt
|
332
334
|
- doc/release_notes/3.74.0.txt
|
333
335
|
- doc/release_notes/3.75.0.txt
|
336
|
+
- doc/release_notes/3.76.0.txt
|
337
|
+
- doc/release_notes/3.77.0.txt
|
334
338
|
- doc/release_notes/3.8.0.txt
|
335
339
|
- doc/release_notes/3.9.0.txt
|
336
340
|
- lib/roda.rb
|
@@ -351,6 +355,7 @@ files:
|
|
351
355
|
- lib/roda/plugins/autoload_named_routes.rb
|
352
356
|
- lib/roda/plugins/backtracking_array.rb
|
353
357
|
- lib/roda/plugins/branch_locals.rb
|
358
|
+
- lib/roda/plugins/break.rb
|
354
359
|
- lib/roda/plugins/caching.rb
|
355
360
|
- lib/roda/plugins/capture_erb.rb
|
356
361
|
- lib/roda/plugins/chunked.rb
|
@@ -494,7 +499,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
494
499
|
- !ruby/object:Gem::Version
|
495
500
|
version: '0'
|
496
501
|
requirements: []
|
497
|
-
rubygems_version: 3.
|
502
|
+
rubygems_version: 3.5.3
|
498
503
|
signing_key:
|
499
504
|
specification_version: 4
|
500
505
|
summary: Routing tree web toolkit
|