rodauth 2.26.1 → 2.28.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: f30e5f8dc756435bee2a6956764516d6697434f507e3226562659807a02b2f0a
4
- data.tar.gz: 71738c31b50b8f82f351eabf0743eb3439cf7519782a10483d16a32a3d0b709b
3
+ metadata.gz: 15ed571757453e13ded3557bd2736779546b2c759230f8ee9070976a0207899e
4
+ data.tar.gz: 9aa5adf648fa1449a75a03d62ae4907f71d41adc49e81fde8da52097042c986c
5
5
  SHA512:
6
- metadata.gz: 7b28515139d2894a9a6164e6ef6f95aebe33b8be4b54548bb4d5c616dd380c7eeb7ff9470c1ac8dc044bbcafb373b596324286f48c860375ed3e1b85aebb6b84
7
- data.tar.gz: 20445419c0e2af068dc3141976cda754e71bfcd96204c1f97215e81764afe4376a58f03cbd6d53c524364e3b56e4ae20ff34904b876a4dcc7beb89254e698b80
6
+ metadata.gz: bdae4bbe3d9c471f967a8b24741504494a4003edce0c265dba9026694d64c08f61bd74cdbf80bded79e3b2c163fe7d273fcf72741f986711891fea5e481c501f
7
+ data.tar.gz: 5c6352c91b52012c6869a149e61887a1a6e0ace76557f2c4922eb699dc4da7f08a1265c5548bff25a3f617fa0a3b565b6d00f3472822d32812ae6261a4bcc95c
data/CHANGELOG CHANGED
@@ -1,3 +1,23 @@
1
+ === 2.28.0 (2023-02-22)
2
+
3
+ * Skip rendering reset password request form on invalid internal request logins (janko) (#303)
4
+
5
+ * Make logged_in? return false if using verify_account_grace_period feature and grace_period has expired (janko) (#300)
6
+
7
+ * Make password_hash method public (janko) (#299)
8
+
9
+ * Add webauthn_key_insert_hash auth method to webauthn feature to control inserts into webauthn keys table (janko) (#298)
10
+
11
+ === 2.27.0 (2023-01-24)
12
+
13
+ * Rename webauth_credentials_for_get to webauthn_credentials_for_get for consistency (janko) (#295)
14
+
15
+ * Hide WebAuthn text inputs by default when using Bootstrap (janko) (#294)
16
+
17
+ * Attempt to avoid database errors when invalid tokens are submitted (jeremyevans)
18
+
19
+ * Allow button template to be overridden just as other templates can be (jeremyevans) (#280)
20
+
1
21
  === 2.26.1 (2022-11-08)
2
22
 
3
23
  * Fix regression in QR code generation in otp feature causing all black QR code (janko) (#279)
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2015-2021 Jeremy Evans
1
+ Copyright (c) 2015-2023 Jeremy Evans
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
data/doc/base.rdoc CHANGED
@@ -35,6 +35,7 @@ cache_templates :: Whether to cache templates. True by default. It may be worth
35
35
  check_csrf? :: Whether Rodauth should use Roda's +check_csrf!+ method for checking CSRF tokens before dispatching to Rodauth routes, true by default.
36
36
  check_csrf_opts :: Options to pass to Roda's +check_csrf!+ if Rodauth calls it before dispatching.
37
37
  check_csrf_block :: Proc for block to pass to Roda's +check_csrf!+ if Rodauth calls it before dispatching.
38
+ convert_token_id_to_integer? :: Whether token ids should be converted to a valid 64-bit integer value. If not set, defaults to true if +account_id_column+ uses an integer type, and false otherwise.
38
39
  default_field_attributes :: The default attributes to use for input field tags, if field_attributes returns nil for the field.
39
40
  default_redirect :: Where to redirect after most successful actions.
40
41
  field_attributes(field) :: The attributes to use for the input field tags for the given field (parameter name).
@@ -96,6 +97,7 @@ before_login_attempt :: Run arbitrary code after an account has been located, bu
96
97
  before_rodauth :: Run arbitrary code before handling any rodauth route, but after CSRF checks if Rodauth is doing CSRF checks.
97
98
  check_csrf :: Checks CSRF token using Roda's +check_csrf!+ method.
98
99
  clear_session :: Clears the current session.
100
+ convert_token_id(id) :: Convert the token id string to an appropriate object to use for the token id (or return +nil+ to signal an invalid token id). By default, converts to a 64-bit signed integer if +convert_token_id_to_integer?+ is true.
99
101
  csrf_tag(path=request.path) :: The HTML fragment containing the CSRF tag to use, if any.
100
102
  function_name(name) :: The name of the database function to call. It's passed either :rodauth_get_salt or :rodauth_valid_password_hash.
101
103
  logged_in? :: Whether the current session is logged in.
@@ -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,35 @@
1
+ = Improvements
2
+
3
+ * Token ids submitting in requests are now converted to integers if
4
+ the configuration uses an integer primary key for the accounts
5
+ table. If the configuration uses a non-integer primary key for
6
+ the accounts table, the convert_token_id configuration method can
7
+ be used, which should return the token id converted to the
8
+ appropriate type, or nil if the token id is not valid for the type.
9
+
10
+ This revised handling avoids raising a database error when an
11
+ invalid token is submitted.
12
+
13
+ * The button template can now be overridden in the same way that
14
+ other Rodauth templates can be overridden.
15
+
16
+ * When using the Bootstrap CSS framework, the text field in the
17
+ Webauthn setup and auth forms is automatically hidden. The text
18
+ field already had a rodauth-hidden class to make it easy to hide
19
+ when using other CSS frameworks.
20
+
21
+ * The email_from and email_to methods are now public instead of
22
+ private.
23
+
24
+ * A nicer error is raised if the Sequel Database object is missing.
25
+
26
+ * A regression in the TOTP QR output that resulted in the QR codes
27
+ being solid black squares has been fixed (this was fixed in
28
+ Rodauth 2.26.1).
29
+
30
+ = Backwards Compatibility
31
+
32
+ * The webauth_credentials_for_get method in the webauthn feature has
33
+ been renamed to webauthn_credentials_for_get for consistency with
34
+ other methods. The webauth_credentials_for_get method will still
35
+ work until Rodauth 3, but will issue deprecation warnings.
@@ -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.
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
- webauth_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.
@@ -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)
@@ -24,6 +24,7 @@ module Rodauth
24
24
  auth_value_method :check_csrf_block, nil
25
25
  auth_value_method :check_csrf_opts, {}.freeze
26
26
  auth_value_method :default_redirect, '/'
27
+ auth_value_method :convert_token_id_to_integer?, nil
27
28
  flash_key :flash_error_key, :error
28
29
  flash_key :flash_notice_key, :notice
29
30
  auth_value_method :hmac_secret, nil
@@ -115,6 +116,7 @@ module Rodauth
115
116
  auth_private_methods(
116
117
  :account_from_login,
117
118
  :account_from_session,
119
+ :convert_token_id,
118
120
  :field_attributes,
119
121
  :field_error_attributes,
120
122
  :formatted_field_error,
@@ -264,7 +266,7 @@ module Rodauth
264
266
  end
265
267
 
266
268
  def db
267
- Sequel::DATABASES.first
269
+ Sequel::DATABASES.first or raise "Sequel database connection is missing"
268
270
  end
269
271
 
270
272
  def password_field_autocomplete_value
@@ -376,10 +378,9 @@ module Rodauth
376
378
  def button_opts(value, opts)
377
379
  opts = Hash[template_opts].merge!(opts)
378
380
  opts[:locals] = {:value=>value, :opts=>opts}
379
- opts[:path] = template_path('button')
380
381
  opts[:cache] = cache_templates
381
382
  opts[:cache_key] = :rodauth_button
382
- opts
383
+ _template_opts(opts, 'button')
383
384
  end
384
385
 
385
386
  def button(value, opts={})
@@ -402,6 +403,11 @@ module Rodauth
402
403
  def post_configure
403
404
  require 'bcrypt' if require_bcrypt?
404
405
  db.extension :date_arithmetic if use_date_arithmetic?
406
+
407
+ if convert_token_id_to_integer?.nil? && (db rescue false) && db.table_exists?(accounts_table) && db.schema(accounts_table).find{|col, v| break v[:type] == :integer if col == account_id_column}
408
+ self.class.send(:define_method, :convert_token_id_to_integer?){true}
409
+ end
410
+
405
411
  route_hash= {}
406
412
  self.class.routes.each do |meth|
407
413
  route_meth = "#{meth.to_s.sub(/\Ahandle_/, '')}_route"
@@ -521,6 +527,25 @@ module Rodauth
521
527
  token.split(token_separator, 2)
522
528
  end
523
529
 
530
+ def convert_token_id(id)
531
+ if convert_token_id_to_integer?
532
+ convert_token_id_to_integer(id)
533
+ else
534
+ id
535
+ end
536
+ end
537
+
538
+ def convert_token_id_to_integer(id)
539
+ if id = (Integer(id, 10) rescue nil)
540
+ if id > 9223372036854775807 || id < -9223372036854775808
541
+ # Only allow 64-bit signed integer range to avoid problems on PostgreSQL
542
+ id = nil
543
+ end
544
+ end
545
+
546
+ id
547
+ end
548
+
524
549
  def redirect(path)
525
550
  request.redirect(path)
526
551
  end
@@ -817,12 +842,16 @@ module Rodauth
817
842
  opts[:locals][:rodauth] = self
818
843
  opts[:cache] = cache_templates
819
844
  opts[:cache_key] = :"rodauth_#{page}"
845
+ _template_opts(opts, page)
846
+ end
820
847
 
848
+ # Set the template path only if there isn't an overridden template in the application.
849
+ # Result should replace existing template opts.
850
+ def _template_opts(opts, page)
821
851
  opts = scope.send(:find_template, scope.send(:parse_template_opts, page, opts))
822
852
  unless File.file?(scope.send(:template_path, opts))
823
853
  opts[:path] = template_path(page)
824
854
  end
825
-
826
855
  opts
827
856
  end
828
857
 
@@ -23,6 +23,14 @@ module Rodauth
23
23
  require 'mail' if require_mail?
24
24
  end
25
25
 
26
+ def email_from
27
+ "webmaster@#{domain}"
28
+ end
29
+
30
+ def email_to
31
+ account[login_column]
32
+ end
33
+
26
34
  private
27
35
 
28
36
  def send_email(email)
@@ -42,14 +50,6 @@ module Rodauth
42
50
  m
43
51
  end
44
52
 
45
- def email_from
46
- "webmaster@#{domain}"
47
- end
48
-
49
- def email_to
50
- account[login_column]
51
- end
52
-
53
53
  def token_link(route, param, key)
54
54
  route_url(route, param => token_param_value(key))
55
55
  end
@@ -64,6 +64,7 @@ module Rodauth
64
64
 
65
65
  def account_from_key(token, status_id=nil)
66
66
  id, key = split_token(token)
67
+ id = convert_token_id(id)
67
68
  return unless id && key
68
69
 
69
70
  return unless actual = yield(id)
@@ -107,7 +107,7 @@ module Rodauth
107
107
  def before_webauthn_auth_route
108
108
  super if defined?(super)
109
109
  if use_json? && !param_or_nil(webauthn_auth_param)
110
- cred = webauth_credential_options_for_get
110
+ cred = webauthn_credential_options_for_get
111
111
  json_response[webauthn_auth_param] = cred.as_json
112
112
  json_response[webauthn_auth_challenge_param] = cred.challenge
113
113
  json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
@@ -117,7 +117,7 @@ module Rodauth
117
117
  def before_webauthn_login_route
118
118
  super if defined?(super)
119
119
  if use_json? && !param_or_nil(webauthn_auth_param) && account_from_login(param(login_param))
120
- cred = webauth_credential_options_for_get
120
+ cred = webauthn_credential_options_for_get
121
121
  json_response[webauthn_auth_param] = cred.as_json
122
122
  json_response[webauthn_auth_challenge_param] = cred.challenge
123
123
  json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
@@ -112,7 +112,7 @@ module Rodauth
112
112
  id, token_id, key = _account_refresh_token_split(token)
113
113
 
114
114
  unless key &&
115
- (id == session_value.to_s) &&
115
+ (id.to_s == session_value.to_s) &&
116
116
  (actual = get_active_refresh_token(id, token_id)) &&
117
117
  timing_safe_eql?(key, convert_token_key(actual)) &&
118
118
  jwt_refresh_token_match?(key)
@@ -126,9 +126,11 @@ module Rodauth
126
126
 
127
127
  def _account_refresh_token_split(token)
128
128
  id, token = split_token(token)
129
+ id = convert_token_id(id)
129
130
  return unless id && token
130
131
 
131
132
  token_id, key = split_token(token)
133
+ token_id = convert_token_id(token_id)
132
134
  return unless token_id && key
133
135
 
134
136
  [id, token_id, key]
@@ -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
 
@@ -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
@@ -102,13 +102,16 @@ module Rodauth
102
102
  :valid_new_webauthn_credential?,
103
103
  :valid_webauthn_credential_auth?,
104
104
  :webauthn_auth_js_path,
105
- :webauth_credential_options_for_get,
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,
109
110
  :webauthn_user_name,
110
111
  )
111
112
 
113
+ def_deprecated_alias :webauthn_credential_options_for_get, :webauth_credential_options_for_get
114
+
112
115
  route(:webauthn_auth_js) do |r|
113
116
  before_webauthn_auth_js_route
114
117
  r.get do
@@ -315,7 +318,7 @@ module Rodauth
315
318
  webauthn_credential.verify(challenge)
316
319
  end
317
320
 
318
- def webauth_credential_options_for_get
321
+ def webauthn_credential_options_for_get
319
322
  WebAuthn::Credential.options_for_get(
320
323
  :allow => account_webauthn_ids,
321
324
  :timeout => webauthn_auth_timeout,
@@ -346,12 +349,7 @@ module Rodauth
346
349
  end
347
350
 
348
351
  def add_webauthn_credential(webauthn_credential)
349
- webauthn_keys_ds.insert(
350
- webauthn_keys_account_id_column => webauthn_account_id,
351
- webauthn_keys_webauthn_id_column => webauthn_credential.id,
352
- webauthn_keys_public_key_column => webauthn_credential.public_key,
353
- webauthn_keys_sign_count_column => Integer(webauthn_credential.sign_count)
354
- )
352
+ webauthn_keys_ds.insert(webauthn_key_insert_hash(webauthn_credential))
355
353
  super if defined?(super)
356
354
  nil
357
355
  end
@@ -433,6 +431,15 @@ module Rodauth
433
431
  super
434
432
  end
435
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
+
436
443
  def webauthn_account_id
437
444
  session_value
438
445
  end
@@ -6,11 +6,11 @@ module Rodauth
6
6
  MAJOR = 2
7
7
 
8
8
  # The minor version of Rodauth, updated for new feature releases of Rodauth.
9
- MINOR = 26
9
+ MINOR = 28
10
10
 
11
11
  # The patch version of Rodauth, updated only for bug fixes from the last
12
12
  # feature release.
13
- TINY = 1
13
+ TINY = 0
14
14
 
15
15
  # The full version of Rodauth as a string
16
16
  VERSION = "#{MAJOR}.#{MINOR}.#{TINY}".freeze
@@ -1,9 +1,9 @@
1
- <form method="post" action="#{rodauth.webauthn_auth_form_path}" class="rodauth" role="form" id="webauthn-auth-form" data-credential-options="#{h((cred = rodauth.webauth_credential_options_for_get).as_json.to_json)}">
1
+ <form method="post" action="#{rodauth.webauthn_auth_form_path}" class="rodauth" role="form" id="webauthn-auth-form" data-credential-options="#{h((cred = rodauth.webauthn_credential_options_for_get).as_json.to_json)}">
2
2
  #{rodauth.webauthn_auth_additional_form_tags}
3
3
  #{rodauth.csrf_tag(rodauth.webauthn_auth_form_path)}
4
4
  <input type="hidden" name="#{rodauth.webauthn_auth_challenge_param}" value="#{cred.challenge}" />
5
5
  <input type="hidden" name="#{rodauth.webauthn_auth_challenge_hmac_param}" value="#{rodauth.compute_hmac(cred.challenge)}" />
6
- <input class="rodauth_hidden" aria-hidden="true" type="text" name="#{rodauth.webauthn_auth_param}" id="webauthn-auth" value="" />
6
+ <input class="rodauth_hidden d-none" aria-hidden="true" type="text" name="#{rodauth.webauthn_auth_param}" id="webauthn-auth" value="" />
7
7
  <div id="webauthn-auth-button">
8
8
  #{rodauth.button(rodauth.webauthn_auth_button)}
9
9
  </div>
@@ -3,7 +3,7 @@
3
3
  #{rodauth.csrf_tag}
4
4
  <input type="hidden" name="#{rodauth.webauthn_setup_challenge_param}" value="#{cred.challenge}" />
5
5
  <input type="hidden" name="#{rodauth.webauthn_setup_challenge_hmac_param}" value="#{rodauth.compute_hmac(cred.challenge)}" />
6
- <input class="rodauth_hidden" aria-hidden="true" type="text" name="#{rodauth.webauthn_setup_param}" id="webauthn-setup" value="" />
6
+ <input class="rodauth_hidden d-none" aria-hidden="true" type="text" name="#{rodauth.webauthn_setup_param}" id="webauthn-setup" value="" />
7
7
  #{rodauth.render('password-field') if rodauth.two_factor_modifications_require_password?}
8
8
  <div id="webauthn-setup-button">
9
9
  #{rodauth.button(rodauth.webauthn_setup_button)}
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.26.1
4
+ version: 2.28.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: 2022-11-08 00:00:00.000000000 Z
11
+ date: 2023-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -342,6 +342,8 @@ extra_rdoc_files:
342
342
  - doc/release_notes/2.24.0.txt
343
343
  - doc/release_notes/2.25.0.txt
344
344
  - doc/release_notes/2.26.0.txt
345
+ - doc/release_notes/2.27.0.txt
346
+ - doc/release_notes/2.28.0.txt
345
347
  - doc/release_notes/2.3.0.txt
346
348
  - doc/release_notes/2.4.0.txt
347
349
  - doc/release_notes/2.5.0.txt
@@ -455,6 +457,8 @@ files:
455
457
  - doc/release_notes/2.24.0.txt
456
458
  - doc/release_notes/2.25.0.txt
457
459
  - doc/release_notes/2.26.0.txt
460
+ - doc/release_notes/2.27.0.txt
461
+ - doc/release_notes/2.28.0.txt
458
462
  - doc/release_notes/2.3.0.txt
459
463
  - doc/release_notes/2.4.0.txt
460
464
  - doc/release_notes/2.5.0.txt
@@ -612,7 +616,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
612
616
  - !ruby/object:Gem::Version
613
617
  version: '0'
614
618
  requirements: []
615
- rubygems_version: 3.3.7
619
+ rubygems_version: 3.4.6
616
620
  signing_key:
617
621
  specification_version: 4
618
622
  summary: Authentication and Account Management Framework for Rack Applications