roda 3.79.0 → 3.81.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.80.0.txt +31 -0
- data/doc/release_notes/3.81.0.txt +24 -0
- data/lib/roda/plugins/assets.rb +3 -1
- data/lib/roda/plugins/exception_page.rb +1 -1
- data/lib/roda/plugins/filter_common_logger.rb +1 -1
- data/lib/roda/plugins/hmac_paths.rb +158 -11
- data/lib/roda/plugins/indifferent_params.rb +0 -3
- data/lib/roda/plugins/not_found.rb +1 -1
- data/lib/roda/plugins/route_csrf.rb +1 -1
- data/lib/roda/plugins/sessions.rb +1 -1
- data/lib/roda/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a9d94f31e568bd2774c3e582152f0bcdbffdf3fcd7e5a95241e73b3fd5b7ac3c
|
|
4
|
+
data.tar.gz: b9ad44642acdbaa0035cbd6ece521ca3432d2e7c23d75a331172ecd6c6288c60
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1cd64e84b47a1a7a01d9165d16e14d95d2c43287b58f2557d9492a201832c1388157152eab1fd12052c7691e3969e5ce1cb9c0ad706e73ad6de822dcc29e1590
|
|
7
|
+
data.tar.gz: 86320c603d0c9b90e2c82f16cc5229b76afe66dde5bdbccce9b28ce076e80808a35410098fe0eae5cb3f5b3180b79f4265b3d525e7861a9dd65890315d274fad
|
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
= 3.81.0 (2024-06-12)
|
|
2
|
+
|
|
3
|
+
* Make assets plugin :early_hints option follow Rack 3 SPEC if using Rack 3 (jeremyevans)
|
|
4
|
+
|
|
5
|
+
* Correctly parse Ruby 3.4 backtraces in exception_page plugin (jeremyevans)
|
|
6
|
+
|
|
7
|
+
* Support :until and :seconds option in hmac_paths plugin, for paths valid only until a specific time (jeremyevans)
|
|
8
|
+
|
|
9
|
+
= 3.80.0 (2024-05-10)
|
|
10
|
+
|
|
11
|
+
* Support :namespace option in hmac_paths plugin, allowing for easy per-user/per-group HMAC paths (jeremyevans)
|
|
12
|
+
|
|
1
13
|
= 3.79.0 (2024-04-12)
|
|
2
14
|
|
|
3
15
|
* Do not update template mtime when there is an error reloading templates in the render plugin (jeremyevans)
|
|
@@ -0,0 +1,31 @@
|
|
|
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.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
= New Features
|
|
2
|
+
|
|
3
|
+
* The hmac_paths plugin now supports :until and :seconds options for
|
|
4
|
+
hmac_path, to create a path that is only valid for a specific amount of
|
|
5
|
+
time. :until sets a specific time that the path will be valid until,
|
|
6
|
+
and :seconds makes the path only valid for the given number of seconds.
|
|
7
|
+
|
|
8
|
+
hmac_path('/widget/1', until: Time.utc(2100))
|
|
9
|
+
# => "/dc8b6e56e4cbe7815df7880d42f0e02956b2e4c49881b6060ceb0e49745a540d/t/4102444800/widget/1"
|
|
10
|
+
|
|
11
|
+
Requests for the path after the given time will not be matched by
|
|
12
|
+
r.hmac_path.
|
|
13
|
+
|
|
14
|
+
= Other Improvements
|
|
15
|
+
|
|
16
|
+
* The early_hints plugin now correctly follows the Rack 3 SPEC when
|
|
17
|
+
using Rack 3. This was not caught previously because Rack only
|
|
18
|
+
added official support for early_hints in the last month.
|
|
19
|
+
|
|
20
|
+
* Ruby 3.4 backtraces are now parsed correctly in the exception_page
|
|
21
|
+
plugin.
|
|
22
|
+
|
|
23
|
+
* Some plugins that accept a block no longer issue an unused block
|
|
24
|
+
warning on Ruby 3.4.
|
data/lib/roda/plugins/assets.rb
CHANGED
|
@@ -736,7 +736,9 @@ class Roda
|
|
|
736
736
|
paths = assets_paths(type)
|
|
737
737
|
if o[:early_hints]
|
|
738
738
|
early_hint_as = ltype == :js ? 'script' : 'style'
|
|
739
|
-
|
|
739
|
+
early_hints = paths.map{|p| "<#{p}>; rel=preload; as=#{early_hint_as}"}
|
|
740
|
+
early_hints = early_hints.join("\n") if Rack.release < '3'
|
|
741
|
+
send_early_hints(RodaResponseHeaders::LINK=>early_hints)
|
|
740
742
|
end
|
|
741
743
|
paths.map{|p| "#{tag_start}#{h(p)}#{tag_end}"}.join("\n")
|
|
742
744
|
end
|
|
@@ -245,7 +245,7 @@ END
|
|
|
245
245
|
|
|
246
246
|
frames = exception.backtrace.map.with_index do |line, i|
|
|
247
247
|
frame = {:id=>i}
|
|
248
|
-
if line =~ /\A(.*?):(\d+)(?::in `(.*)')?\Z/
|
|
248
|
+
if line =~ /\A(.*?):(\d+)(?::in [`'](.*)')?\Z/
|
|
249
249
|
filename = frame[:filename] = $1
|
|
250
250
|
lineno = frame[:lineno] = $2.to_i
|
|
251
251
|
frame[:function] = $3
|
|
@@ -112,13 +112,53 @@ class Roda
|
|
|
112
112
|
# this for POST requests (or other HTTP verbs that can have request bodies), use +r.GET+
|
|
113
113
|
# instead of +r.params+ to specifically check query string parameters.
|
|
114
114
|
#
|
|
115
|
-
#
|
|
115
|
+
# The generated paths can be timestamped, so that they are only valid until a given time
|
|
116
|
+
# or for a given number of seconds after they are generated, using the :until or :seconds
|
|
117
|
+
# options:
|
|
116
118
|
#
|
|
117
|
-
# hmac_path('/1',
|
|
118
|
-
# # =>
|
|
119
|
+
# hmac_path('/widget/1', until: Time.utc(2100))
|
|
120
|
+
# # => "/dc8b6e56e4cbe7815df7880d42f0e02956b2e4c49881b6060ceb0e49745a540d/t/4102444800/widget/1"
|
|
121
|
+
#
|
|
122
|
+
# hmac_path('/widget/1', seconds: Time.utc(2100).to_i - Time.now.to_i)
|
|
123
|
+
# # => "/dc8b6e56e4cbe7815df7880d42f0e02956b2e4c49881b6060ceb0e49745a540d/t/4102444800/widget/1"
|
|
124
|
+
#
|
|
125
|
+
# The :namespace option, if provided, should be a string, and it modifies the generated HMACs
|
|
126
|
+
# to only match those in the same namespace. This can be used to provide different paths to
|
|
127
|
+
# different users or groups of users.
|
|
128
|
+
#
|
|
129
|
+
# hmac_path('/widget/1', namespace: '1')
|
|
130
|
+
# # => "/3793ac2a72ea399c40cbd63f154d19f0fe34cdf8d347772134c506a0b756d590/n/widget/1"
|
|
131
|
+
#
|
|
132
|
+
# hmac_path('/widget/1', namespace: '2')
|
|
133
|
+
# # => "/0e1e748860d4fd17fe9b7c8259b1e26996502c38e465f802c2c9a0a13000087c/n/widget/1"
|
|
134
|
+
#
|
|
135
|
+
# The +r.hmac_path+ method accepts a :namespace option, and if a :namespace option is
|
|
136
|
+
# provided, it will only match an hmac path if the namespace given matches the one used
|
|
137
|
+
# when the hmac path was created.
|
|
138
|
+
#
|
|
139
|
+
# r.hmac_path(namespace: '1'){}
|
|
140
|
+
# # will match "/3793ac2a72ea399c40cbd63f154d19f0fe34cdf8d347772134c506a0b756d590/n/widget/1"
|
|
141
|
+
# # will not match "/0e1e748860d4fd17fe9b7c8259b1e26996502c38e465f802c2c9a0a13000087c/n/widget/1"
|
|
142
|
+
#
|
|
143
|
+
# The most common use of the :namespace option is to reference session values, so the value of
|
|
144
|
+
# each path depends on the logged in user. You can use the +:namespace_session_key+ plugin
|
|
145
|
+
# option to set the default namespace for both +hmac_path+ and +r.hmac_path+:
|
|
146
|
+
#
|
|
147
|
+
# plugin :hmac_paths, secret: 'some-secret-value-with-at-least-32-bytes',
|
|
148
|
+
# namespace_session_key: 'account_id'
|
|
149
|
+
#
|
|
150
|
+
# This will use <tt>session['account_id']</tt> as the default namespace for both +hmac_path+
|
|
151
|
+
# and +r.hmac_path+ (if the session value is not nil, it is converted to a string using +to_s+).
|
|
152
|
+
# You can override the default namespace by passing a +:namespace+ option when calling +hmac_path+
|
|
153
|
+
# and +r.hmac_path+.
|
|
154
|
+
#
|
|
155
|
+
# You can use +:root+, +:method+, +:params+, and +:namespace+ at the same time:
|
|
156
|
+
#
|
|
157
|
+
# hmac_path('/1', root: '/widget', method: :get, params: {foo: 'bar'}, namespace: '1')
|
|
158
|
+
# # => "/widget/c14c78a81d34d766cf334a3ddbb7a6b231bc2092ef50a77ded0028586027b14e/mpn/1?foo=bar"
|
|
119
159
|
#
|
|
120
160
|
# This gives you a path only valid for a GET request with a root of <tt>/widget</tt> and
|
|
121
|
-
# a query string of <tt>foo=bar</tt
|
|
161
|
+
# a query string of <tt>foo=bar</tt>, using namespace +1+.
|
|
122
162
|
#
|
|
123
163
|
# To handle secret rotation, you can provide an +:old_secret+ option when loading the
|
|
124
164
|
# plugin.
|
|
@@ -128,6 +168,48 @@ class Roda
|
|
|
128
168
|
#
|
|
129
169
|
# This will use +:secret+ for constructing new paths, but will respect paths generated by
|
|
130
170
|
# +:old_secret+.
|
|
171
|
+
#
|
|
172
|
+
# = HMAC Construction
|
|
173
|
+
#
|
|
174
|
+
# This describes the internals for how HMACs are constructed based on the options provided
|
|
175
|
+
# to +hmac_path+. In the examples below:
|
|
176
|
+
#
|
|
177
|
+
# * +HMAC+ is the raw HMAC-SHA256 output (first argument is secret, second is data)
|
|
178
|
+
# * +HMAC_hex+ is the hexidecimal version of +HMAC+
|
|
179
|
+
# * +secret+ is the plugin :secret option
|
|
180
|
+
#
|
|
181
|
+
# The +:secret+ plugin option is never used directly as the HMAC secret. All HMACs are
|
|
182
|
+
# generated with a root-specific secret. The root will be the empty if no +:root+ option
|
|
183
|
+
# is given. The hmac path flags are always included in the hmac calculation, prepended to the
|
|
184
|
+
# path:
|
|
185
|
+
#
|
|
186
|
+
# r.hmac_path('/1')
|
|
187
|
+
# HMAC_hex(HMAC_hex(secret, ''), '/0/1')
|
|
188
|
+
#
|
|
189
|
+
# r.hmac_path('/1', root: '/2')
|
|
190
|
+
# HMAC_hex(HMAC_hex(secret, '/2'), '/0/1')
|
|
191
|
+
#
|
|
192
|
+
# The +:method+ option uses an uppercase version of the method prepended to the path. This
|
|
193
|
+
# cannot conflict with the path itself, since paths must start with a slash.
|
|
194
|
+
#
|
|
195
|
+
# r.hmac_path('/1', method: :get)
|
|
196
|
+
# HMAC_hex(HMAC_hex(secret, ''), 'GET:/m/1')
|
|
197
|
+
#
|
|
198
|
+
# The +:params+ option includes the query string for the params in the HMAC:
|
|
199
|
+
#
|
|
200
|
+
# r.hmac_path('/1', params: {k: 2})
|
|
201
|
+
# HMAC_hex(HMAC_hex(secret, ''), '/p/1?k=2')
|
|
202
|
+
#
|
|
203
|
+
# The +:until+ and +:seconds+ option include the timestamp in the HMAC:
|
|
204
|
+
#
|
|
205
|
+
# r.hmac_path('/1', until: Time.utc(2100))
|
|
206
|
+
# HMAC_hex(HMAC_hex(secret, ''), '/t/4102444800/1')
|
|
207
|
+
#
|
|
208
|
+
# If a +:namespace+ option is provided, the original secret used before the +:root+ option is
|
|
209
|
+
# an HMAC of the +:secret+ plugin option and the given namespace.
|
|
210
|
+
#
|
|
211
|
+
# r.hmac_path('/1', namespace: '2')
|
|
212
|
+
# HMAC_hex(HMAC_hex(HMAC(secret, '2'), ''), '/n/1')
|
|
131
213
|
module HmacPaths
|
|
132
214
|
def self.configure(app, opts=OPTS)
|
|
133
215
|
hmac_secret = opts[:secret]
|
|
@@ -143,6 +225,10 @@ class Roda
|
|
|
143
225
|
|
|
144
226
|
app.opts[:hmac_paths_secret] = hmac_secret
|
|
145
227
|
app.opts[:hmac_paths_old_secret] = hmac_old_secret
|
|
228
|
+
|
|
229
|
+
if opts[:namespace_session_key]
|
|
230
|
+
app.opts[:hmac_paths_namespace_session_key] = opts[:namespace_session_key]
|
|
231
|
+
end
|
|
146
232
|
end
|
|
147
233
|
|
|
148
234
|
module InstanceMethods
|
|
@@ -152,12 +238,17 @@ class Roda
|
|
|
152
238
|
# valid paths. The given path should be a string starting with +/+. Options:
|
|
153
239
|
#
|
|
154
240
|
# :method :: Limits the returned path to only be valid for the given request method.
|
|
241
|
+
# :namespace :: Make the HMAC value depend on the given namespace. If this is not
|
|
242
|
+
# provided, the default namespace is used. To explicitly not use a
|
|
243
|
+
# namespace when there is a default namespace, pass a nil value.
|
|
155
244
|
# :params :: Includes parameters in the query string of the returned path, and
|
|
156
245
|
# limits the returned path to only be valid for that exact query string.
|
|
157
246
|
# :root :: Should be an empty string or string starting with +/+. This will be
|
|
158
247
|
# the already matched path of the routing tree using r.hmac_path. Defaults
|
|
159
248
|
# to the empty string, which will returns paths valid for r.hmac_path at
|
|
160
249
|
# the top level of the routing tree.
|
|
250
|
+
# :seconds :: Make the given path valid for the given integer number of seconds.
|
|
251
|
+
# :until :: Make the given path valid until the given Time.
|
|
161
252
|
def hmac_path(path, opts=OPTS)
|
|
162
253
|
unless path.is_a?(String) && path.getbyte(0) == 47
|
|
163
254
|
raise RodaError, "path must be a string starting with /"
|
|
@@ -168,6 +259,12 @@ class Roda
|
|
|
168
259
|
raise RodaError, "root must be empty string or string starting with /"
|
|
169
260
|
end
|
|
170
261
|
|
|
262
|
+
if valid_until = opts[:until]
|
|
263
|
+
valid_until = valid_until.to_i
|
|
264
|
+
elsif seconds = opts[:seconds]
|
|
265
|
+
valid_until = Time.now.to_i + seconds
|
|
266
|
+
end
|
|
267
|
+
|
|
171
268
|
flags = String.new
|
|
172
269
|
path = path.dup
|
|
173
270
|
|
|
@@ -180,6 +277,15 @@ class Roda
|
|
|
180
277
|
path << '?' << Rack::Utils.build_query(params)
|
|
181
278
|
end
|
|
182
279
|
|
|
280
|
+
if hmac_path_namespace(opts)
|
|
281
|
+
flags << 'n'
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
if valid_until
|
|
285
|
+
flags << 't'
|
|
286
|
+
path = "/#{valid_until}#{path}"
|
|
287
|
+
end
|
|
288
|
+
|
|
183
289
|
flags << '0' if flags.empty?
|
|
184
290
|
|
|
185
291
|
hmac_path = if method
|
|
@@ -188,7 +294,7 @@ class Roda
|
|
|
188
294
|
"/#{flags}#{path}"
|
|
189
295
|
end
|
|
190
296
|
|
|
191
|
-
"#{root}/#{hmac_path_hmac(root, hmac_path)}/#{flags}#{path}"
|
|
297
|
+
"#{root}/#{hmac_path_hmac(root, hmac_path, opts)}/#{flags}#{path}"
|
|
192
298
|
end
|
|
193
299
|
|
|
194
300
|
# The HMAC to use in hmac_path, for the given root, path, and options.
|
|
@@ -196,14 +302,34 @@ class Roda
|
|
|
196
302
|
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, hmac_path_hmac_secret(root, opts), path)
|
|
197
303
|
end
|
|
198
304
|
|
|
305
|
+
# The namespace to use for the hmac path. If a :namespace option is not
|
|
306
|
+
# provided, and a :namespace_session_key option was provided, this will
|
|
307
|
+
# use the value of the related session key, if present.
|
|
308
|
+
def hmac_path_namespace(opts=OPTS)
|
|
309
|
+
opts.fetch(:namespace){hmac_path_default_namespace}
|
|
310
|
+
end
|
|
311
|
+
|
|
199
312
|
private
|
|
200
313
|
|
|
201
314
|
# The secret used to calculate the HMAC in hmac_path. This is itself an HMAC, created
|
|
202
|
-
# using the secret given in the plugin, for the given root and options.
|
|
315
|
+
# using the secret given in the plugin, for the given root and options.
|
|
316
|
+
# This always returns a hexidecimal string.
|
|
203
317
|
def hmac_path_hmac_secret(root, opts=OPTS)
|
|
204
318
|
secret = opts[:secret] || self.opts[:hmac_paths_secret]
|
|
319
|
+
|
|
320
|
+
if namespace = hmac_path_namespace(opts)
|
|
321
|
+
secret = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, secret, namespace)
|
|
322
|
+
end
|
|
323
|
+
|
|
205
324
|
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, secret, root)
|
|
206
325
|
end
|
|
326
|
+
|
|
327
|
+
# The default namespace to use for hmac_path, if a :namespace option is not provided.
|
|
328
|
+
def hmac_path_default_namespace
|
|
329
|
+
if (key = opts[:hmac_paths_namespace_session_key]) && (value = session[key])
|
|
330
|
+
value.to_s
|
|
331
|
+
end
|
|
332
|
+
end
|
|
207
333
|
end
|
|
208
334
|
|
|
209
335
|
module RequestMethods
|
|
@@ -221,6 +347,13 @@ class Roda
|
|
|
221
347
|
if submitted_hmac.bytesize == 64
|
|
222
348
|
on String do |flags|
|
|
223
349
|
if flags.bytesize >= 1
|
|
350
|
+
if flags.include?('n') ^ !scope.hmac_path_namespace(opts).nil?
|
|
351
|
+
# Namespace required and not provided, or provided and not required.
|
|
352
|
+
# Bail early to avoid unnecessary HMAC calculation.
|
|
353
|
+
@remaining_path = orig_path
|
|
354
|
+
return
|
|
355
|
+
end
|
|
356
|
+
|
|
224
357
|
if flags.include?('m')
|
|
225
358
|
rpath = "#{env['REQUEST_METHOD'].to_s.upcase}:#{rpath}"
|
|
226
359
|
end
|
|
@@ -229,8 +362,20 @@ class Roda
|
|
|
229
362
|
rpath = "#{rpath}?#{env["QUERY_STRING"]}"
|
|
230
363
|
end
|
|
231
364
|
|
|
232
|
-
if hmac_path_valid?(mpath, rpath, submitted_hmac)
|
|
233
|
-
|
|
365
|
+
if hmac_path_valid?(mpath, rpath, submitted_hmac, opts)
|
|
366
|
+
if flags.include?('t')
|
|
367
|
+
on Integer do |int|
|
|
368
|
+
if int >= Time.now.to_i
|
|
369
|
+
always(&block)
|
|
370
|
+
else
|
|
371
|
+
# Return from method without matching
|
|
372
|
+
@remaining_path = orig_path
|
|
373
|
+
return
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
else
|
|
377
|
+
always(&block)
|
|
378
|
+
end
|
|
234
379
|
end
|
|
235
380
|
end
|
|
236
381
|
|
|
@@ -249,11 +394,13 @@ class Roda
|
|
|
249
394
|
private
|
|
250
395
|
|
|
251
396
|
# Determine whether the provided hmac matches.
|
|
252
|
-
def hmac_path_valid?(root, path, hmac)
|
|
253
|
-
if Rack::Utils.secure_compare(scope.hmac_path_hmac(root, path), hmac)
|
|
397
|
+
def hmac_path_valid?(root, path, hmac, opts=OPTS)
|
|
398
|
+
if Rack::Utils.secure_compare(scope.hmac_path_hmac(root, path, opts), hmac)
|
|
254
399
|
true
|
|
255
400
|
elsif old_secret = roda_class.opts[:hmac_paths_old_secret]
|
|
256
|
-
|
|
401
|
+
opts = opts.dup
|
|
402
|
+
opts[:secret] = old_secret
|
|
403
|
+
Rack::Utils.secure_compare(scope.hmac_path_hmac(root, path, opts), hmac)
|
|
257
404
|
else
|
|
258
405
|
false
|
|
259
406
|
end
|
|
@@ -53,13 +53,10 @@ class Roda
|
|
|
53
53
|
|
|
54
54
|
class Params < Rack::QueryParser::Params
|
|
55
55
|
if Rack.release >= '3'
|
|
56
|
-
# rack main branch compatibility
|
|
57
|
-
# :nocov:
|
|
58
56
|
if Params < Hash
|
|
59
57
|
def initialize
|
|
60
58
|
super(&INDIFFERENT_PROC)
|
|
61
59
|
end
|
|
62
|
-
# :nocov:
|
|
63
60
|
else
|
|
64
61
|
def initialize
|
|
65
62
|
@size = 0
|
|
@@ -476,7 +476,7 @@ class Roda
|
|
|
476
476
|
serialized_data << json_data
|
|
477
477
|
|
|
478
478
|
cipher_secret = opts[:cipher_secret]
|
|
479
|
-
if
|
|
479
|
+
if opts[:per_cookie_cipher_secret]
|
|
480
480
|
version = "\1"
|
|
481
481
|
per_cookie_secret_base = SecureRandom.random_bytes(32)
|
|
482
482
|
cipher_secret = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, cipher_secret, per_cookie_secret_base)
|
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.81.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: 2024-
|
|
11
|
+
date: 2024-06-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|
|
@@ -254,6 +254,8 @@ extra_rdoc_files:
|
|
|
254
254
|
- doc/release_notes/3.78.0.txt
|
|
255
255
|
- doc/release_notes/3.79.0.txt
|
|
256
256
|
- doc/release_notes/3.8.0.txt
|
|
257
|
+
- doc/release_notes/3.80.0.txt
|
|
258
|
+
- doc/release_notes/3.81.0.txt
|
|
257
259
|
- doc/release_notes/3.9.0.txt
|
|
258
260
|
files:
|
|
259
261
|
- CHANGELOG
|
|
@@ -340,6 +342,8 @@ files:
|
|
|
340
342
|
- doc/release_notes/3.78.0.txt
|
|
341
343
|
- doc/release_notes/3.79.0.txt
|
|
342
344
|
- doc/release_notes/3.8.0.txt
|
|
345
|
+
- doc/release_notes/3.80.0.txt
|
|
346
|
+
- doc/release_notes/3.81.0.txt
|
|
343
347
|
- doc/release_notes/3.9.0.txt
|
|
344
348
|
- lib/roda.rb
|
|
345
349
|
- lib/roda/cache.rb
|
|
@@ -505,7 +509,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
505
509
|
- !ruby/object:Gem::Version
|
|
506
510
|
version: '0'
|
|
507
511
|
requirements: []
|
|
508
|
-
rubygems_version: 3.5.
|
|
512
|
+
rubygems_version: 3.5.9
|
|
509
513
|
signing_key:
|
|
510
514
|
specification_version: 4
|
|
511
515
|
summary: Routing tree web toolkit
|