rodauth 2.26.1 → 2.28.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 +20 -0
- data/MIT-LICENSE +1 -1
- data/doc/base.rdoc +2 -0
- data/doc/guides/password_requirements.rdoc +15 -2
- data/doc/json.rdoc +8 -0
- data/doc/release_notes/2.27.0.txt +35 -0
- data/doc/release_notes/2.28.0.txt +16 -0
- data/doc/webauthn.rdoc +2 -1
- data/lib/rodauth/features/argon2.rb +12 -12
- data/lib/rodauth/features/base.rb +33 -4
- data/lib/rodauth/features/email_base.rb +9 -8
- data/lib/rodauth/features/json.rb +2 -2
- data/lib/rodauth/features/jwt_refresh.rb +3 -1
- data/lib/rodauth/features/login_password_requirements_base.rb +4 -4
- data/lib/rodauth/features/password_pepper.rb +2 -2
- data/lib/rodauth/features/reset_password.rb +1 -1
- data/lib/rodauth/features/verify_account_grace_period.rb +4 -0
- data/lib/rodauth/features/webauthn.rb +15 -8
- data/lib/rodauth/version.rb +2 -2
- data/templates/webauthn-auth.str +2 -2
- data/templates/webauthn-setup.str +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: 15ed571757453e13ded3557bd2736779546b2c759230f8ee9070976a0207899e
|
4
|
+
data.tar.gz: 9aa5adf648fa1449a75a03d62ae4907f71d41adc49e81fde8da52097042c986c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
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
|
-
|
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 =
|
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 =
|
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
|
@@ -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
|
-
:
|
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
|
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
|
data/lib/rodauth/version.rb
CHANGED
@@ -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 =
|
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 =
|
13
|
+
TINY = 0
|
14
14
|
|
15
15
|
# The full version of Rodauth as a string
|
16
16
|
VERSION = "#{MAJOR}.#{MINOR}.#{TINY}".freeze
|
data/templates/webauthn-auth.str
CHANGED
@@ -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.
|
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.
|
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:
|
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.
|
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
|