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 +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
|