roda 3.72.0 → 3.73.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5c28e38d35f59176f159798f68d82bbd30df62a5907ace3a3750b1daf7b4fe6
4
- data.tar.gz: cb5fd8d5a9d665bc820c55ccbf1fd6a068873ae3e265a1f877bbdf82b51c4d6e
3
+ metadata.gz: 7a47f703af806a15f523b99b38d084520bada92f23196374d6d9781d5953faa8
4
+ data.tar.gz: 4612153820b89e6dbcfa2370c04269666c49277d8f11256869f6c1f0bb0b571a
5
5
  SHA512:
6
- metadata.gz: d8710537511b8f332c443fd41bd279c99de53c0bc9618cd92f763ab7d354f70c4496ba9eafa076438087b5ab52f36e69f649aa00d2fb6f07d5315b7d61aef4a1
7
- data.tar.gz: e0af216b465facc81e81ab8a495d472685c26aa6b2c1d56c0e48631586555f78f4d5922ac5ee92c6118a08b8162ee35866dc5708155bdbed70d5851b2ff8339b
6
+ metadata.gz: bdc42cdc9540750195327dac290e3f0bb08c3ed0100b610441b644c85849e7e9f9f974013cea041cdf640f590e2027996d68b62eea9c31d41bd42a57df6530bb
7
+ data.tar.gz: 3ab05db704cf45803ad706e78b558ea7798d8d9782a06c7dec79814a4d862582249e5554946c59fff88e1f1d2d360e242268c593a8c9c95fe87b5489e4a4a44c
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ = 3.73.0 (2023-10-13)
2
+
3
+ * Support :next_if_not_found option for middleware plugin (jeremyevans) (#334)
4
+
5
+ * Remove dependency on base64 library from sessions and route_csrf plugin, as it will not be part of the standard library in Ruby 3.4+ (jeremyevans)
6
+
1
7
  = 3.72.0 (2023-09-12)
2
8
 
3
9
  * Add invalid_request_body plugin for custom handling of invalid request bodies (jeremyevans)
@@ -0,0 +1,33 @@
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.
@@ -0,0 +1,34 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ module Base64_
7
+ class << self
8
+ if RUBY_VERSION >= '2.4'
9
+ def decode64(str)
10
+ str.unpack1("m0")
11
+ end
12
+ # :nocov:
13
+ else
14
+ def decode64(str)
15
+ str.unpack("m0")[0]
16
+ end
17
+ # :nocov:
18
+ end
19
+
20
+ def urlsafe_encode64(bin)
21
+ str = [bin].pack("m0")
22
+ str.tr!("+/", "-_")
23
+ str
24
+ end
25
+
26
+ def urlsafe_decode64(str)
27
+ decode64(str.tr("-_", "+/"))
28
+ end
29
+ end
30
+ end
31
+
32
+ register_plugin(:_base64, Base64_)
33
+ end
34
+ end
@@ -411,7 +411,7 @@ END
411
411
 
412
412
  private
413
413
 
414
- if RUBY_VERSION >= '3.2'
414
+ if Exception.method_defined?(:detailed_message)
415
415
  def exception_page_exception_message(exception)
416
416
  exception.detailed_message(highlight: false).to_s
417
417
  end
@@ -33,6 +33,43 @@ class Roda
33
33
  #
34
34
  # run App
35
35
  #
36
+ # By default, when the app is used as middleware and handles the request at
37
+ # all, it does not forward the request to the next middleware. For the
38
+ # following setup:
39
+ #
40
+ # class Mid < Roda
41
+ # plugin :middleware
42
+ #
43
+ # route do |r|
44
+ # r.on "foo" do
45
+ # r.is "mid" do
46
+ # "Mid"
47
+ # end
48
+ # end
49
+ # end
50
+ # end
51
+ #
52
+ # class App < Roda
53
+ # use Mid
54
+ #
55
+ # route do |r|
56
+ # r.on "foo" do
57
+ # r.is "app" do
58
+ # "App"
59
+ # end
60
+ # end
61
+ # end
62
+ # end
63
+ #
64
+ # run App
65
+ #
66
+ # Requests for +/foo/mid will+ return +Mid+, but requests for +/foo/app+
67
+ # will return an empty 404 response, because the middleware handles the
68
+ # +/foo/app+ request in the <tt>r.on "foo" do</tt> block, but does not
69
+ # have the block return a result, which Roda treats as an empty 404 response.
70
+ # If you would like the middleware to forward +/foo/app+ request to the
71
+ # application, you should use the +:next_if_not_found+ plugin option.
72
+ #
36
73
  # It is possible to use the Roda app as a regular app even when using
37
74
  # the middleware plugin. Using an app as middleware automatically creates
38
75
  # a subclass of the app for the middleware. Because a subclass is automatically
@@ -64,6 +101,9 @@ class Roda
64
101
  # # Request to App for /mid returns
65
102
  # # "foo bar baz"
66
103
  module Middleware
104
+ NEXT_PROC = lambda{throw :next, true}
105
+ private_constant :NEXT_PROC
106
+
67
107
  # Configure the middleware plugin. Options:
68
108
  # :env_var :: Set the environment variable to use to indicate to the roda
69
109
  # application that the current request is a middleware request.
@@ -77,12 +117,15 @@ class Roda
77
117
  # the middleware's route block should be applied to the
78
118
  # final response when the request is forwarded to the app.
79
119
  # Defaults to false.
120
+ # :next_if_not_found :: If the middleware handles the request but returns a not found
121
+ # result (404 with no body), forward the result to the next middleware.
80
122
  def self.configure(app, opts={}, &block)
81
123
  app.opts[:middleware_env_var] = opts[:env_var] if opts.has_key?(:env_var)
82
124
  app.opts[:middleware_env_var] ||= 'roda.forward_next'
83
125
  app.opts[:middleware_configure] = block if block
84
126
  app.opts[:middleware_handle_result] = opts[:handle_result]
85
127
  app.opts[:middleware_forward_response_headers] = opts[:forward_response_headers]
128
+ app.opts[:middleware_next_if_not_found] = opts[:next_if_not_found]
86
129
  end
87
130
 
88
131
  # Forwarder instances are what is actually used as middleware.
@@ -91,6 +134,9 @@ class Roda
91
134
  # and store +app+ as the next middleware to call.
92
135
  def initialize(mid, app, *args, &block)
93
136
  @mid = Class.new(mid)
137
+ if @mid.opts[:middleware_next_if_not_found]
138
+ @mid.plugin(:not_found, &NEXT_PROC)
139
+ end
94
140
  if configure = @mid.opts[:middleware_configure]
95
141
  configure.call(@mid, *args, &block)
96
142
  elsif block || !args.empty?
@@ -1,6 +1,5 @@
1
1
  # frozen-string-literal: true
2
2
 
3
- require 'base64'
4
3
  require 'openssl'
5
4
  require 'securerandom'
6
5
  require 'uri'
@@ -163,6 +162,10 @@ class Roda
163
162
  # a valid CSRF token was not provided.
164
163
  class InvalidToken < RodaError; end
165
164
 
165
+ def self.load_dependencies(app, opts=OPTS)
166
+ app.plugin :_base64
167
+ end
168
+
166
169
  def self.configure(app, opts=OPTS, &block)
167
170
  options = app.opts[:route_csrf] = (app.opts[:route_csrf] || DEFAULTS).merge(opts)
168
171
  if block || opts[:csrf_failure].is_a?(Proc)
@@ -260,7 +263,7 @@ class Roda
260
263
  def csrf_token(path=nil, method=('POST' if path))
261
264
  token = SecureRandom.random_bytes(31)
262
265
  token << csrf_hmac(token, method, path)
263
- Base64.strict_encode64(token)
266
+ [token].pack("m0")
264
267
  end
265
268
 
266
269
  # Whether request-specific CSRF tokens should be used by default.
@@ -314,7 +317,7 @@ class Roda
314
317
  end
315
318
 
316
319
  begin
317
- submitted_hmac = Base64.strict_decode64(encoded_token)
320
+ submitted_hmac = Base64_.decode64(encoded_token)
318
321
  rescue ArgumentError
319
322
  return "encoded token is not valid base64"
320
323
  end
@@ -354,7 +357,7 @@ class Roda
354
357
  # JSON is used for session serialization).
355
358
  def csrf_secret
356
359
  key = session[csrf_options[:key]] ||= SecureRandom.base64(32)
357
- Base64.strict_decode64(key)
360
+ Base64_.decode64(key)
358
361
  end
359
362
  end
360
363
  end
@@ -10,7 +10,6 @@ rescue OpenSSL::Cipher::CipherError
10
10
  # :nocov:
11
11
  end
12
12
 
13
- require 'base64'
14
13
  require 'json'
15
14
  require 'securerandom'
16
15
  require 'zlib'
@@ -171,6 +170,10 @@ class Roda
171
170
  [cipher_secret.freeze, hmac_secret.freeze]
172
171
  end
173
172
 
173
+ def self.load_dependencies(app, opts=OPTS)
174
+ app.plugin :_base64
175
+ end
176
+
174
177
  # Configure the plugin, see Sessions for details on options.
175
178
  def self.configure(app, opts=OPTS)
176
179
  opts = (app.opts[:sessions] || DEFAULT_OPTIONS).merge(opts)
@@ -344,7 +347,7 @@ class Roda
344
347
  opts = roda_class.opts[:sessions]
345
348
 
346
349
  begin
347
- data = Base64.urlsafe_decode64(data)
350
+ data = Base64_.urlsafe_decode64(data)
348
351
  rescue ArgumentError
349
352
  return _session_serialization_error("Unable to decode session: invalid base64")
350
353
  end
@@ -493,7 +496,7 @@ class Roda
493
496
  data << encrypted_data
494
497
  data << OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, opts[:hmac_secret], data+opts[:key])
495
498
 
496
- data = Base64.urlsafe_encode64(data)
499
+ data = Base64_.urlsafe_encode64(data)
497
500
 
498
501
  if data.bytesize >= 4096
499
502
  raise CookieTooLarge, "attempted to create cookie larger than 4096 bytes"
data/lib/roda/version.rb CHANGED
@@ -4,7 +4,7 @@ class Roda
4
4
  RodaMajorVersion = 3
5
5
 
6
6
  # The minor version of Roda, updated for new feature releases of Roda.
7
- RodaMinorVersion = 72
7
+ RodaMinorVersion = 73
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
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.72.0
4
+ version: 3.73.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: 2023-09-12 00:00:00.000000000 Z
11
+ date: 2023-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -246,6 +246,7 @@ extra_rdoc_files:
246
246
  - doc/release_notes/3.70.0.txt
247
247
  - doc/release_notes/3.71.0.txt
248
248
  - doc/release_notes/3.72.0.txt
249
+ - doc/release_notes/3.73.0.txt
249
250
  - doc/release_notes/3.8.0.txt
250
251
  - doc/release_notes/3.9.0.txt
251
252
  files:
@@ -325,6 +326,7 @@ files:
325
326
  - doc/release_notes/3.70.0.txt
326
327
  - doc/release_notes/3.71.0.txt
327
328
  - doc/release_notes/3.72.0.txt
329
+ - doc/release_notes/3.73.0.txt
328
330
  - doc/release_notes/3.8.0.txt
329
331
  - doc/release_notes/3.9.0.txt
330
332
  - lib/roda.rb
@@ -332,6 +334,7 @@ files:
332
334
  - lib/roda/plugins.rb
333
335
  - lib/roda/plugins/Integer_matcher_max.rb
334
336
  - lib/roda/plugins/_after_hook.rb
337
+ - lib/roda/plugins/_base64.rb
335
338
  - lib/roda/plugins/_before_hook.rb
336
339
  - lib/roda/plugins/_optimized_matching.rb
337
340
  - lib/roda/plugins/_symbol_regexp_matchers.rb