rodauth 2.27.0 → 2.29.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: eeb08d35b1a9cf7c0a5393bbcf831d41fa0ff1a9d822761ef63c149723d79db2
4
- data.tar.gz: 8a890d1659b1a0634960420ab0546db1e76363dad7c43dc01a0b05dfe4cc85e3
3
+ metadata.gz: c1714e5a3a0a5bbae56f2905dd528611de3b958d505d312071148b56fdfb3d6f
4
+ data.tar.gz: 8bb57c30ced05b0825a5d1fd74efe9f6523202f1b151b591c0bbdf10ad9f12af
5
5
  SHA512:
6
- metadata.gz: 1e27b99b1fa245aab6c600257fc82fcae6789d31105047d06d39eae185064d08917359ba8eb631b94dcfa7aa6a05be77e700a8935070b8467bcac25bbd3e2cb1
7
- data.tar.gz: 71bfbebd641cc594889fa4d82086a17b250388796990d24b8240acb6e668fe41b52f9b1727b4b8b49846cc13574b398da0ae7c4f092436d027a4719df96f0e75
6
+ metadata.gz: 4dfc0639aaebdeacf6961122265720c992fb0d1af5d7864f5984fa902eef0ae49aea30db63681b1bdd1c598458f8ce5b035fdb3192249f3983afba15442bf990
7
+ data.tar.gz: d044a6934b3d06bee1e260de68ca5a88016b6f611da1e59dabf1e16afc63e7a82c6d16d196ed57a23558c14a0d6aecba4030ece7830a4f0a6211260b1e619b50
data/CHANGELOG CHANGED
@@ -1,3 +1,25 @@
1
+ === 2.29.0 (2023-03-22)
2
+
3
+ * Support :render=>false plugin options (davekaro) (#319)
4
+
5
+ * Add remove_active_session method for removing the active session for a given session id (janko) (#317)
6
+
7
+ * Remove current active session when adding new active session (janko) (#314)
8
+
9
+ * Extend the remember cookie deadline once an hour by default while logged in (janko, jeremyevans) (#313)
10
+
11
+ * Add account! method for returning associated account or loading account based on the session value (janko) (#309)
12
+
13
+ === 2.28.0 (2023-02-22)
14
+
15
+ * Skip rendering reset password request form on invalid internal request logins (janko) (#303)
16
+
17
+ * Make logged_in? return false if using verify_account_grace_period feature and grace_period has expired (janko) (#300)
18
+
19
+ * Make password_hash method public (janko) (#299)
20
+
21
+ * Add webauthn_key_insert_hash auth method to webauthn feature to control inserts into webauthn keys table (janko) (#298)
22
+
1
23
  === 2.27.0 (2023-01-24)
2
24
 
3
25
  * Rename webauth_credentials_for_get to webauthn_credentials_for_get for consistency (janko) (#295)
data/README.rdoc CHANGED
@@ -79,7 +79,8 @@ There are some dependencies that Rodauth uses depending on the
79
79
  features in use. These are development dependencies instead of
80
80
  runtime dependencies in the gem as it is possible to run without them:
81
81
 
82
- tilt :: Used by all features unless in JSON API only mode.
82
+ tilt :: Used by all features unless in JSON API only mode or using
83
+ :render=>false plugin option.
83
84
  rack_csrf :: Used for CSRF support if the <tt>csrf: :rack_csrf</tt> plugin
84
85
  option is given (the default is to use Roda's route_csrf
85
86
  plugin, as that allows for more secure request-specific
@@ -852,6 +853,8 @@ which configures which dependent plugins should be loaded. Options:
852
853
  :csrf :: Set to +false+ to not load a csrf plugin. Set to +:rack_csrf+
853
854
  to use the csrf plugin instead of the route_csrf plugin.
854
855
  :flash :: Set to +false+ to not load the flash plugin
856
+ :render :: Set to +false+ to not load the render plugin. This is useful
857
+ to avoid the dependency on tilt when using alternative view libaries.
855
858
  :json :: Set to +true+ to load the json and json_parser plugins. Set
856
859
  to +:only+ to only load those plugins and not any other plugins.
857
860
  Note that if you are enabling features that send email, you
@@ -1000,6 +1003,8 @@ logged_in? :: Whether the session has been logged in.
1000
1003
  authenticated? :: Similar to +logged_in?+, but if the account has setup two
1001
1004
  factor authentication, whether the session has authenticated
1002
1005
  via two factors.
1006
+ account! :: Returns the current account record if it has already been loaded,
1007
+ otherwise retrieves the account from session if logged in.
1003
1008
  authenticated_by :: An array of strings for successful authentication methods for
1004
1009
  the current session (e.g. password/remember/webauthn).
1005
1010
  possible_authentication_methods :: An array of strings for possible authentication
@@ -48,6 +48,7 @@ add_active_session :: Create a session id for the session and populate the sessi
48
48
  currently_active_session? :: Whether the session is currently active, by checking the database table.
49
49
  handle_duplicate_active_session_id(exception) :: How to handle the case where a duplicate session id for the account is inserted into the table. Does nothing by default. This should only be called if the random number generator is broken.
50
50
  no_longer_active_session :: What action to take if +rodauth.check_active_session+ is called and the session is no longer active.
51
+ remove_active_session(session_id) :: Removes the active session matching the given session ID from the database. Useful for implementing session revoking.
51
52
  remove_all_active_sessions :: Remove all active session from the database, used for global logouts and when closing accounts.
52
53
  remove_current_session :: Remove current session from the database, used for regular logouts.
53
54
  remove_inactive_sessions :: Remove inactive sessions from the database, run before checking for whether the current session is active.
@@ -1,13 +1,16 @@
1
1
  = Customize password requirements
2
2
 
3
3
  By default, Rodauth requires passwords to have at least 6 characters. You can
4
- modify the minimum length:
4
+ modify the minimum and maximum length:
5
5
 
6
6
  plugin :rodauth do
7
7
  enable :login, :logout, :create_account
8
8
 
9
9
  # Require passwords to have at least 8 characters
10
10
  password_minimum_length 8
11
+
12
+ # Don't allow passwords to be too long, to prevent long password DoS attacks
13
+ password_maximum_length 64
11
14
  end
12
15
 
13
16
  You can use the {disallow common passwords feature}[rdoc-ref:doc/disallow_common_passwords.rdoc]
@@ -25,6 +28,16 @@ can use the <tt>password_meets_requirements?</tt> configuration method.
25
28
  enable :login, :logout, :create_account
26
29
 
27
30
  password_meets_requirements? do |password|
28
- #true if password meets requirements, false otherwise
31
+ super(password) && password_complex_enough?(password)
32
+ end
33
+
34
+ auth_class_eval do
35
+ # If password doesn't pass custom validation, add field error with error
36
+ # reason, and return false.
37
+ def password_complex_enough?(password)
38
+ return true if password.match?(/\d/) && password.match?(/[^a-zA-Z\d]/)
39
+ set_password_requirement_error_message(:password_simple, "requires one number and one special character")
40
+ false
41
+ end
29
42
  end
30
43
  end
data/doc/json.rdoc CHANGED
@@ -15,6 +15,14 @@ an array containing the field name and the error message for that field.
15
15
  Successful requests by default store a +success+ entry with a success
16
16
  message, though that can be disabled.
17
17
 
18
+ The JSON response can be modified at any point by modifying the +json_response+
19
+ hash. The following example adds an {error reason}[rdoc-ref:doc/error_reasons.rdoc]
20
+ to the JSON response:
21
+
22
+ set_error_reason do |reason|
23
+ json_response[:error_reason] = reason
24
+ end
25
+
18
26
  The session state is managed in the rack session, so make sure that
19
27
  CSRF protection is enabled. This will be the case when passing the
20
28
  <tt>json: true</tt> option when loading the rodauth plugin. If you
@@ -0,0 +1,16 @@
1
+ = New Features
2
+
3
+ * A webauthn_key_insert_hash configuration method has been added when
4
+ using the webauthn feature, making it easier to add new columns to
5
+ the webauthn key data, such as a custom name for the authenticator.
6
+
7
+ = Other Improvements
8
+
9
+ * When using the verify_account_grace_period feature, logged_in? now
10
+ returns false for sessions where the grace period has expired.
11
+
12
+ * When using the internal_request and reset_password features,
13
+ submitting an internal request for an invalid login no longer tries
14
+ to render a reset password request form.
15
+
16
+ * The password_hash method is now public.
@@ -0,0 +1,27 @@
1
+ = New Features
2
+
3
+ * When using the remember feature, by default, the remember deadline
4
+ is extended while logged in, if it hasn't been extended in the last
5
+ hour
6
+
7
+ * An account! method has been added, which will return the hash for
8
+ the account if already retrieved, or attempt to retrieve the
9
+ account hash using the currently logged in session if not.
10
+ Because of the ambiguity in the provenance of the returned account
11
+ hash, callers should be careful when using this method.
12
+
13
+ * A remove_active_session method has been added. You can call this
14
+ method with a specific session id, and it will remove the related
15
+ active session.
16
+
17
+ * A render: false plugin option is now support, which will disable
18
+ the automatic loading of the render plugin. This should only be
19
+ used if you are completely replacing Rodauth's view rendering with
20
+ your own.
21
+
22
+ = Other Improvements
23
+
24
+ * When logging in when using the active_sessions feature, if there is
25
+ a current active session, it is removed before a new active session
26
+ is created. This prevents some stale active sessions from remaining
27
+ in the database (which would eventually be cleaned up later).
data/doc/remember.rdoc CHANGED
@@ -30,13 +30,15 @@ for sessions autologged in via a remember token:
30
30
 
31
31
  == Auth Value Methods
32
32
 
33
- extend_remember_deadline? :: Whether to extend the remember token deadline when the user is autologged in via remember token.
33
+ extend_remember_deadline? :: Whether to extend the remember token deadline when the user is autologged in via remember token and every +extend_remember_deadline_period+ seconds while logged in.
34
+ extend_remember_deadline_period :: The amount of seconds to wait before extending remember token deadline when +extend_remember_deadline?+ is true (3600 by default).
34
35
  raw_remember_token_deadline :: A deadline before which to allow a raw remember token to be used. Allows for graceful transition for when +hmac_secret+ is first set.
35
36
  remember_additional_form_tags :: HTML fragment containing additional form tags to use on the change remember setting form.
36
37
  remember_button :: The text to use for the change remember settings button.
37
38
  remember_cookie_key :: The cookie name to use for the remember token.
38
39
  remember_cookie_options :: Any options to set for the remember cookie. By default, the `:path` cookie option is set to `/` and `:httponly` is set to `true`. Also, `:secure` is set to `true` by default if the current request is an HTTPS request.
39
40
  remember_deadline_column :: The column name in the +remember_table+ storing the deadline after which the token will be ignored.
41
+ remember_deadline_extended_session_key :: The session key set if the remember deadline token is being extended.
40
42
  remember_deadline_interval :: The amount of time for which to remember accounts, 14 days by default. Only used if +set_deadline_values?+ is true.
41
43
  remember_disable_label :: The label for disabling remembering.
42
44
  remember_disable_param_value :: The parameter value for disabling remembering.
data/doc/webauthn.rdoc CHANGED
@@ -104,9 +104,10 @@ remove_all_webauthn_keys_and_user_ids :: Remove all WebAuthn credentials and the
104
104
  remove_webauthn_key(webauthn_id) :: Remove the WebAuthn credential with the given WebAuthn ID from the current account.
105
105
  valid_new_webauthn_credential?(webauthn_credential) :: Check wheck the WebAuthn credential provided by the client during registration is valid.
106
106
  valid_webauthn_credential_auth?(webauthn_credential) :: Check wheck the WebAuthn credential provided by the client during authentication is valid.
107
- webauthn_credential_options_for_get :: WebAuthn credential options to provide to the client during WebAuthn authentication.
108
107
  webauthn_auth_js_path :: The path to the WebAuthn authentication javascript.
109
108
  webauthn_auth_view :: The HTML to use for the page for authenticating via WebAuthn.
109
+ webauthn_credential_options_for_get :: WebAuthn credential options to provide to the client during WebAuthn authentication.
110
+ webauthn_key_insert_hash(webauthn_credential) :: The hash to insert into the +webauthn_keys_table+.
110
111
  webauthn_remove_authenticated_session :: Remove the authenticated WebAuthn ID, used when removing the WebAuthn credential with the ID after authenticating with it.
111
112
  webauthn_remove_view :: The HTML to use for the page for removing an existing WebAuthn authenticator.
112
113
  webauthn_setup_js_path :: The path to the WebAuthn registration javascript.
@@ -29,6 +29,7 @@ module Rodauth
29
29
  :currently_active_session?,
30
30
  :handle_duplicate_active_session_id,
31
31
  :no_longer_active_session,
32
+ :remove_active_session,
32
33
  :remove_all_active_sessions,
33
34
  :remove_current_session,
34
35
  :remove_inactive_sessions,
@@ -82,10 +83,14 @@ module Rodauth
82
83
 
83
84
  def remove_current_session
84
85
  if session_id = session[session_id_session_key]
85
- active_sessions_ds.where(active_sessions_session_id_column=>compute_hmac(session_id)).delete
86
+ remove_active_session(compute_hmac(session_id))
86
87
  end
87
88
  end
88
89
 
90
+ def remove_active_session(session_id)
91
+ active_sessions_ds.where(active_sessions_session_id_column=>session_id).delete
92
+ end
93
+
89
94
  def remove_all_active_sessions
90
95
  active_sessions_ds.delete
91
96
  end
@@ -101,6 +106,7 @@ module Rodauth
101
106
  end
102
107
 
103
108
  def update_session
109
+ remove_current_session
104
110
  super
105
111
  add_active_session
106
112
  end
@@ -15,6 +15,18 @@ module Rodauth
15
15
  auth_value_method :argon2_secret, nil
16
16
  auth_value_method :use_argon2?, true
17
17
 
18
+ def password_hash(password)
19
+ return super unless use_argon2?
20
+
21
+ if secret = argon2_secret
22
+ argon2_params = Hash[password_hash_cost]
23
+ argon2_params[:secret] = secret
24
+ else
25
+ argon2_params = password_hash_cost
26
+ end
27
+ ::Argon2::Password.new(argon2_params).create(password)
28
+ end
29
+
18
30
  private
19
31
 
20
32
  if Argon2::VERSION != '2.1.0'
@@ -34,18 +46,6 @@ module Rodauth
34
46
  argon2_hash_cost
35
47
  end
36
48
 
37
- def password_hash(password)
38
- return super unless use_argon2?
39
-
40
- if secret = argon2_secret
41
- argon2_params = Hash[password_hash_cost]
42
- argon2_params[:secret] = secret
43
- else
44
- argon2_params = password_hash_cost
45
- end
46
- ::Argon2::Password.new(argon2_params).create(password)
47
- end
48
-
49
49
  def password_hash_match?(hash, password)
50
50
  return super unless argon2_hash_algorithm?(hash)
51
51
  argon2_password_hash_match?(hash, password)
@@ -355,6 +355,10 @@ module Rodauth
355
355
  account_open_status_value
356
356
  end
357
357
 
358
+ def account!
359
+ account || (session_value && account_from_session)
360
+ end
361
+
358
362
  def account_from_session
359
363
  @account = _account_from_session
360
364
  end
@@ -680,7 +684,7 @@ module Rodauth
680
684
  # note that only the salt is returned.
681
685
  def get_password_hash
682
686
  if account_password_hash_column
683
- (account || account_from_session)[account_password_hash_column]
687
+ account![account_password_hash_column]
684
688
  elsif use_database_authentication_functions?
685
689
  db.get(Sequel.function(function_name(:rodauth_get_salt), account ? account_id : session_value))
686
690
  else
@@ -75,6 +75,10 @@ module Rodauth
75
75
  hash
76
76
  end
77
77
 
78
+ def password_hash(password)
79
+ BCrypt::Password.create(password, :cost=>password_hash_cost)
80
+ end
81
+
78
82
  private
79
83
 
80
84
  attr_reader :login_requirement_message
@@ -184,9 +188,5 @@ module Rodauth
184
188
  def extract_password_hash_cost(hash)
185
189
  hash[4, 2].to_i
186
190
  end
187
-
188
- def password_hash(password)
189
- BCrypt::Password.create(password, :cost=>password_hash_cost)
190
- end
191
191
  end
192
192
  end
@@ -16,12 +16,12 @@ module Rodauth
16
16
  result
17
17
  end
18
18
 
19
- private
20
-
21
19
  def password_hash(password)
22
20
  super(password + password_pepper.to_s)
23
21
  end
24
22
 
23
+ private
24
+
25
25
  def password_hash_match?(hash, password)
26
26
  return super if password_pepper.nil?
27
27
 
@@ -17,6 +17,7 @@ module Rodauth
17
17
  auth_value_method :raw_remember_token_deadline, nil
18
18
  auth_value_method :remember_cookie_options, {}.freeze
19
19
  auth_value_method :extend_remember_deadline?, false
20
+ auth_value_method :extend_remember_deadline_period, 3600
20
21
  auth_value_method :remember_period, {:days=>14}.freeze
21
22
  auth_value_method :remember_deadline_interval, {:days=>14}.freeze
22
23
  auth_value_method :remember_id_column, :id
@@ -28,6 +29,7 @@ module Rodauth
28
29
  auth_value_method :remember_remember_param_value, 'remember'
29
30
  auth_value_method :remember_forget_param_value, 'forget'
30
31
  auth_value_method :remember_disable_param_value, 'disable'
32
+ session_key :remember_deadline_extended_session_key, :remember_deadline_extended_at
31
33
  translatable_method :remember_remember_label, 'Remember Me'
32
34
  translatable_method :remember_forget_label, 'Forget Me'
33
35
  translatable_method :remember_disable_label, 'Disable Remember Me'
@@ -110,43 +112,23 @@ module Rodauth
110
112
  end
111
113
 
112
114
  def load_memory
113
- return if session[session_key]
114
-
115
- unless id = remembered_session_id
116
- # Only set expired cookie if there is already a cookie set.
117
- forget_login if _get_remember_cookie
118
- return
119
- end
120
-
121
- set_session_value(session_key, id)
122
- account = account_from_session
123
- remove_session_value(session_key)
124
-
125
- unless account
126
- remove_remember_key(id)
127
- forget_login
128
- return
129
- end
130
-
131
- before_load_memory
132
- login_session('remember')
133
-
134
- if extend_remember_deadline?
135
- active_remember_key_ds(id).update(remember_deadline_column=>Sequel.date_add(Sequel::CURRENT_TIMESTAMP, remember_period))
136
- remember_login
115
+ if logged_in?
116
+ if extend_remember_deadline_while_logged_in?
117
+ account_from_session
118
+ extend_remember_deadline
119
+ end
120
+ elsif account_from_remember_cookie
121
+ before_load_memory
122
+ login_session('remember')
123
+ extend_remember_deadline if extend_remember_deadline?
124
+ after_load_memory
137
125
  end
138
- after_load_memory
139
126
  end
140
127
 
141
128
  def remember_login
142
129
  get_remember_key
143
- opts = Hash[remember_cookie_options]
144
- opts[:value] = "#{account_id}_#{convert_token_key(remember_key_value)}"
145
- opts[:expires] = convert_timestamp(active_remember_key_ds.get(remember_deadline_column))
146
- opts[:path] = "/" unless opts.key?(:path)
147
- opts[:httponly] = true unless opts.key?(:httponly) || opts.key?(:http_only)
148
- opts[:secure] = true unless opts.key?(:secure) || !request.ssl?
149
- ::Rack::Utils.set_cookie_header!(response.headers, remember_cookie_key, opts)
130
+ set_remember_cookie
131
+ set_session_value(remember_deadline_extended_session_key, Time.now.to_i) if extend_remember_deadline?
150
132
  end
151
133
 
152
134
  def forget_login
@@ -191,6 +173,53 @@ module Rodauth
191
173
 
192
174
  private
193
175
 
176
+ def set_remember_cookie
177
+ opts = Hash[remember_cookie_options]
178
+ opts[:value] = "#{account_id}_#{convert_token_key(remember_key_value)}"
179
+ opts[:expires] = convert_timestamp(active_remember_key_ds.get(remember_deadline_column))
180
+ opts[:path] = "/" unless opts.key?(:path)
181
+ opts[:httponly] = true unless opts.key?(:httponly) || opts.key?(:http_only)
182
+ opts[:secure] = true unless opts.key?(:secure) || !request.ssl?
183
+ ::Rack::Utils.set_cookie_header!(response.headers, remember_cookie_key, opts)
184
+ end
185
+
186
+ def extend_remember_deadline_while_logged_in?
187
+ return false unless extend_remember_deadline?
188
+
189
+ if extended_at = session[remember_deadline_extended_session_key]
190
+ extended_at + extend_remember_deadline_period < Time.now.to_i
191
+ elsif logged_in_via_remember_key?
192
+ # Handle existing sessions before the change to extend remember deadline
193
+ # while logged in.
194
+ true
195
+ end
196
+ end
197
+
198
+ def extend_remember_deadline
199
+ active_remember_key_ds.update(remember_deadline_column=>Sequel.date_add(Sequel::CURRENT_TIMESTAMP, remember_period))
200
+ remember_login
201
+ end
202
+
203
+ def account_from_remember_cookie
204
+ unless id = remembered_session_id
205
+ # Only set expired cookie if there is already a cookie set.
206
+ forget_login if _get_remember_cookie
207
+ return
208
+ end
209
+
210
+ set_session_value(session_key, id)
211
+ account_from_session
212
+ remove_session_value(session_key)
213
+
214
+ unless account
215
+ remove_remember_key(id)
216
+ forget_login
217
+ return
218
+ end
219
+
220
+ account
221
+ end
222
+
194
223
  def _get_remember_cookie
195
224
  request.cookies[remember_cookie_key]
196
225
  end
@@ -219,7 +219,7 @@ module Rodauth
219
219
  attr_reader :reset_password_key_value
220
220
 
221
221
  def after_login_failure
222
- unless only_json?
222
+ unless only_json? || internal_request?
223
223
  @login_form_header = login_failed_reset_password_request_form
224
224
  end
225
225
  super
@@ -30,6 +30,10 @@ module Rodauth
30
30
  false
31
31
  end
32
32
 
33
+ def logged_in?
34
+ super && !unverified_grace_period_expired?
35
+ end
36
+
33
37
  def require_login
34
38
  if unverified_grace_period_expired?
35
39
  clear_session
@@ -79,7 +83,7 @@ module Rodauth
79
83
  end
80
84
 
81
85
  def account_in_unverified_grace_period?
82
- return false unless account || (session_value && account_from_session)
86
+ return false unless account!
83
87
  account[account_status_column] == account_unverified_status_value &&
84
88
  verify_account_grace_period &&
85
89
  !verify_account_ds.where(Sequel.date_add(verification_requested_at_column, :seconds=>verify_account_grace_period) > Sequel::CURRENT_TIMESTAMP).empty?
@@ -103,6 +103,7 @@ module Rodauth
103
103
  :valid_webauthn_credential_auth?,
104
104
  :webauthn_auth_js_path,
105
105
  :webauthn_credential_options_for_get,
106
+ :webauthn_key_insert_hash,
106
107
  :webauthn_remove_authenticated_session,
107
108
  :webauthn_setup_js_path,
108
109
  :webauthn_update_session,
@@ -328,7 +329,7 @@ module Rodauth
328
329
  end
329
330
 
330
331
  def webauthn_user_name
331
- (account || account_from_session)[login_column]
332
+ account![login_column]
332
333
  end
333
334
 
334
335
  def webauthn_origin
@@ -348,12 +349,7 @@ module Rodauth
348
349
  end
349
350
 
350
351
  def add_webauthn_credential(webauthn_credential)
351
- webauthn_keys_ds.insert(
352
- webauthn_keys_account_id_column => webauthn_account_id,
353
- webauthn_keys_webauthn_id_column => webauthn_credential.id,
354
- webauthn_keys_public_key_column => webauthn_credential.public_key,
355
- webauthn_keys_sign_count_column => Integer(webauthn_credential.sign_count)
356
- )
352
+ webauthn_keys_ds.insert(webauthn_key_insert_hash(webauthn_credential))
357
353
  super if defined?(super)
358
354
  nil
359
355
  end
@@ -435,6 +431,15 @@ module Rodauth
435
431
  super
436
432
  end
437
433
 
434
+ def webauthn_key_insert_hash(webauthn_credential)
435
+ {
436
+ webauthn_keys_account_id_column => webauthn_account_id,
437
+ webauthn_keys_webauthn_id_column => webauthn_credential.id,
438
+ webauthn_keys_public_key_column => webauthn_credential.public_key,
439
+ webauthn_keys_sign_count_column => Integer(webauthn_credential.sign_count)
440
+ }
441
+ end
442
+
438
443
  def webauthn_account_id
439
444
  session_value
440
445
  end
@@ -6,7 +6,7 @@ module Rodauth
6
6
  MAJOR = 2
7
7
 
8
8
  # The minor version of Rodauth, updated for new feature releases of Rodauth.
9
- MINOR = 27
9
+ MINOR = 29
10
10
 
11
11
  # The patch version of Rodauth, updated only for bug fixes from the last
12
12
  # feature release.
data/lib/rodauth.rb CHANGED
@@ -22,8 +22,10 @@ module Rodauth
22
22
  end
23
23
 
24
24
  unless json_opt == :only
25
- require 'tilt/string'
26
- app.plugin :render
25
+ unless opts[:render] == false
26
+ require 'tilt/string'
27
+ app.plugin :render
28
+ end
27
29
 
28
30
  case opts.fetch(:csrf, app.opts[:rodauth_csrf])
29
31
  when false
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.27.0
4
+ version: 2.29.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-01-24 00:00:00.000000000 Z
11
+ date: 2023-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -343,6 +343,8 @@ extra_rdoc_files:
343
343
  - doc/release_notes/2.25.0.txt
344
344
  - doc/release_notes/2.26.0.txt
345
345
  - doc/release_notes/2.27.0.txt
346
+ - doc/release_notes/2.28.0.txt
347
+ - doc/release_notes/2.29.0.txt
346
348
  - doc/release_notes/2.3.0.txt
347
349
  - doc/release_notes/2.4.0.txt
348
350
  - doc/release_notes/2.5.0.txt
@@ -457,6 +459,8 @@ files:
457
459
  - doc/release_notes/2.25.0.txt
458
460
  - doc/release_notes/2.26.0.txt
459
461
  - doc/release_notes/2.27.0.txt
462
+ - doc/release_notes/2.28.0.txt
463
+ - doc/release_notes/2.29.0.txt
460
464
  - doc/release_notes/2.3.0.txt
461
465
  - doc/release_notes/2.4.0.txt
462
466
  - doc/release_notes/2.5.0.txt
@@ -614,7 +618,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
614
618
  - !ruby/object:Gem::Version
615
619
  version: '0'
616
620
  requirements: []
617
- rubygems_version: 3.4.1
621
+ rubygems_version: 3.4.6
618
622
  signing_key:
619
623
  specification_version: 4
620
624
  summary: Authentication and Account Management Framework for Rack Applications