rodauth 2.32.0 → 2.34.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 +28 -0
- data/README.rdoc +1 -0
- data/doc/active_sessions.rdoc +3 -1
- data/doc/release_notes/2.33.0.txt +18 -0
- data/doc/release_notes/2.34.0.txt +36 -0
- data/doc/sms_codes.rdoc +2 -0
- data/lib/rodauth/features/active_sessions.rb +14 -0
- data/lib/rodauth/features/base.rb +3 -2
- data/lib/rodauth/features/create_account.rb +1 -1
- data/lib/rodauth/features/email_auth.rb +6 -8
- data/lib/rodauth/features/lockout.rb +6 -8
- data/lib/rodauth/features/login.rb +4 -0
- data/lib/rodauth/features/reset_password.rb +6 -8
- data/lib/rodauth/features/sms_codes.rb +19 -3
- data/lib/rodauth/features/verify_account.rb +6 -8
- data/lib/rodauth/features/verify_login_change.rb +6 -8
- data/lib/rodauth/features/webauthn.rb +56 -16
- data/lib/rodauth/version.rb +1 -1
- data/lib/rodauth.rb +1 -0
- 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: 96f5711d9bb49c87385e4e0ef0f07e0e8624e1139f145429c1a518d844811757
|
|
4
|
+
data.tar.gz: 01c43ee8ceb8d4c61c040e3463bf8b03cdd239e2c401461ef0122a24407ce311
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9b66e0f290cf4ae0c6d14c4032ff0830ef4b229a158def47247bec420414161dcfe35c60de12b15f20ac358d9c55d7ed446bf1d07cb0b6302031b63e5ce4b5a2
|
|
7
|
+
data.tar.gz: 304d17a7a183a0e33e42db2fcb5be6e9cdab0b58a70416ac2abd49478c4a1cc28c62395bd25f0e5b154a8117e712772045994c72159f4d36b3413d5f567c5a2c
|
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
=== 2.34.0 (2024-03-22)
|
|
2
|
+
|
|
3
|
+
* Add remove_all_active_sessions_except_current method for removing current active session (jeremyevans) (#395)
|
|
4
|
+
|
|
5
|
+
* Add remove_all_active_sessions_except_for method for removing active sessions except for given session id (jeremyevans) (#395)
|
|
6
|
+
|
|
7
|
+
* Avoid overriding WebAuthn internals when using webauthn 3 (santiagorodriguez96, jeremyevans) (#398)
|
|
8
|
+
|
|
9
|
+
* Support overriding webauthn_rp_id when verifying Webauthn credentials (butsjoh, jeremyevans) (#397)
|
|
10
|
+
|
|
11
|
+
* Override require_login_redirect in login feature to use login_path (janko) (#396)
|
|
12
|
+
|
|
13
|
+
* Do not override convert_token_id_to_integer? if the user has already configured it (janko) (#393)
|
|
14
|
+
|
|
15
|
+
* Have uses_two_factor_authentication? handle case where account has been deleted (janko) (#390)
|
|
16
|
+
|
|
17
|
+
* Add current_route accessor to allow easy determination of which rodauth route was requested (janko) (#381)
|
|
18
|
+
|
|
19
|
+
=== 2.33.0 (2023-12-21)
|
|
20
|
+
|
|
21
|
+
* Expire SMS confirm code after 24 hours by default (jeremyevans)
|
|
22
|
+
|
|
23
|
+
* Do not accidentally confirm SMS phone number on successful authentication of other second factor (Bertg) (#376, #377)
|
|
24
|
+
|
|
25
|
+
* Return error response instead of 404 response for requests to valid pages with missing tokens (janko) (#375)
|
|
26
|
+
|
|
27
|
+
* Do not override existing primary key value in the cached account when inserting a new account (janko) (#372)
|
|
28
|
+
|
|
1
29
|
=== 2.32.0 (2023-10-23)
|
|
2
30
|
|
|
3
31
|
* Remove use of Base64 in argon2 feature (jeremyevans)
|
data/README.rdoc
CHANGED
|
@@ -830,6 +830,7 @@ scope :: Roda instance
|
|
|
830
830
|
session :: session hash
|
|
831
831
|
flash :: flash message hash
|
|
832
832
|
account :: account hash (if set by an earlier Rodauth method)
|
|
833
|
+
current_route :: route name symbol (if Rodauth is handling the route)
|
|
833
834
|
|
|
834
835
|
So if you want to log the IP address for the user during login:
|
|
835
836
|
|
data/doc/active_sessions.rdoc
CHANGED
|
@@ -49,6 +49,8 @@ currently_active_session? :: Whether the session is currently active, by checkin
|
|
|
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
51
|
remove_active_session(session_id) :: Removes the active session matching the given session ID from the database. Useful for implementing session revoking.
|
|
52
|
-
remove_all_active_sessions :: Remove all active
|
|
52
|
+
remove_all_active_sessions :: Remove all active sessions for the account from the database, used for global logouts and when closing accounts.
|
|
53
|
+
remove_all_active_sessions_except_for(session_id) :: Remove all active sessions for the account from the database, except for the session id given.
|
|
54
|
+
remove_all_active_sessions_except_current :: Remove all active sessions for the account from the database, except for the current session.
|
|
53
55
|
remove_current_session :: Remove current session from the database, used for regular logouts.
|
|
54
56
|
remove_inactive_sessions :: Remove inactive sessions from the database, run before checking for whether the current session is active.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
= Improvements
|
|
2
|
+
|
|
3
|
+
* Rodauth no longer accidentally confirms an SMS number upon valid
|
|
4
|
+
authentication by an alternative second factor.
|
|
5
|
+
|
|
6
|
+
* Rodauth now automatically expires SMS confirmation codes after 24
|
|
7
|
+
hours by default. You can use the sms_confirm_deadline
|
|
8
|
+
configuration method to adjust the deadline. Previously, if an
|
|
9
|
+
invalid SMS number was submitted, or the SMS confirm code was never
|
|
10
|
+
received, it was not possible to continue SMS setup without
|
|
11
|
+
administrative intervention.
|
|
12
|
+
|
|
13
|
+
* Rodauth no longer overwrites existing primary key values when
|
|
14
|
+
inserting new accounts. This fixes cases such as setting account
|
|
15
|
+
primary key values to UUIDs before inserting.
|
|
16
|
+
|
|
17
|
+
* When submitting a request to a valid endpoint with a missing token,
|
|
18
|
+
Rodauth now returns an error response instead of a 404 response.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
= New Features
|
|
2
|
+
|
|
3
|
+
* A rodauth.current_route method has been added for returning the route
|
|
4
|
+
name symbol (if rodauth is currently handling the route). This makes it
|
|
5
|
+
simpler to write code that extends Rodauth and works with
|
|
6
|
+
applications that use override the default route names.
|
|
7
|
+
|
|
8
|
+
* A remove_all_active_sessions_except_for method has been added to the
|
|
9
|
+
active_sessions feature, which removes all active sessions for the
|
|
10
|
+
current account, except for the session id given.
|
|
11
|
+
|
|
12
|
+
* A remove_all_active_sessions_except_current method has been added to
|
|
13
|
+
the active_sessions feature, which removes all active sessions for
|
|
14
|
+
the current account, except for the current session.
|
|
15
|
+
|
|
16
|
+
= Improvements
|
|
17
|
+
|
|
18
|
+
* Rodauth now supports overriding webauthn_rp_id in the webauthn
|
|
19
|
+
feature.
|
|
20
|
+
|
|
21
|
+
* When using the login feature, Rodauth now defaults
|
|
22
|
+
require_login_redirect to use the path to the login route, instead
|
|
23
|
+
of /login.
|
|
24
|
+
|
|
25
|
+
* When setting up multifactor authentication, Rodauth now handles the
|
|
26
|
+
case where account has been deleted, instead of raising an exception.
|
|
27
|
+
|
|
28
|
+
* When a database connection is not available during startup, Rodauth
|
|
29
|
+
now handles that case instead of raising an exception. Note that in
|
|
30
|
+
this case, Rodauth cannot automatically setup a conversion of token
|
|
31
|
+
ids to integer, since it cannot determine whether the underlying
|
|
32
|
+
database column uses an integer type.
|
|
33
|
+
|
|
34
|
+
* When using WebAuthn 3+, Rodauth no longer defines singleton methods
|
|
35
|
+
to work around limitations in WebAuthn. Instead, it uses public
|
|
36
|
+
APIs that were added in WebAuthn 3.
|
data/doc/sms_codes.rdoc
CHANGED
|
@@ -41,6 +41,7 @@ sms_codes_table :: The name of the table storing SMS code data.
|
|
|
41
41
|
sms_confirm_additional_form_tags :: HTML fragment containing additional form tags when confirming SMS setup.
|
|
42
42
|
sms_confirm_button :: Text to use for button on the form to confirm SMS setup.
|
|
43
43
|
sms_confirm_code_length :: The length of SMS confirmation codes, 12 by default, as there is no lockout.
|
|
44
|
+
sms_confirm_deadline :: The number of seconds before an SMS confirmation code expires (86400 seconds by default).
|
|
44
45
|
sms_confirm_notice_flash :: The flash notice to show when SMS authentication setup has been confirmed.
|
|
45
46
|
sms_confirm_page_title :: The page title to use on the form to authenticate via SMS code.
|
|
46
47
|
sms_confirm_redirect :: Where to redirect after SMS authentication setup has been confirmed.
|
|
@@ -125,6 +126,7 @@ sms_new_auth_code :: A new SMS authentication code that can be used for the acco
|
|
|
125
126
|
sms_new_confirm_code :: A new SMS confirmation code that can be used for the account.
|
|
126
127
|
sms_normalize_phone(phone) :: A normalized version of the given phone number, by default removing everything except 0-9.
|
|
127
128
|
sms_record_failure :: Record an SMS authentication failure for the current account.
|
|
129
|
+
sms_remove_expired_confirm_code :: Remove an expired SMS confirm code, allowing setup of a new sms confirm code.
|
|
128
130
|
sms_remove_failures :: Reset the SMS authentication failure counter for the current account, used after a successful multifactor authentication.
|
|
129
131
|
sms_request_response :: Return a response after a successful SMS request during SMS authentication. By default, redirects to +sms_auth_redirect+.
|
|
130
132
|
sms_request_view :: The HTML to use for the form to request an SMS authentication code.
|
|
@@ -31,6 +31,8 @@ module Rodauth
|
|
|
31
31
|
:no_longer_active_session,
|
|
32
32
|
:remove_active_session,
|
|
33
33
|
:remove_all_active_sessions,
|
|
34
|
+
:remove_all_active_sessions_except_for,
|
|
35
|
+
:remove_all_active_sessions_except_current,
|
|
34
36
|
:remove_current_session,
|
|
35
37
|
:remove_inactive_sessions,
|
|
36
38
|
)
|
|
@@ -95,6 +97,18 @@ module Rodauth
|
|
|
95
97
|
active_sessions_ds.delete
|
|
96
98
|
end
|
|
97
99
|
|
|
100
|
+
def remove_all_active_sessions_except_for(session_id)
|
|
101
|
+
active_sessions_ds.exclude(active_sessions_session_id_column=>compute_hmacs(session_id)).delete
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def remove_all_active_sessions_except_current
|
|
105
|
+
if session_id = session[session_id_session_key]
|
|
106
|
+
remove_all_active_sessions_except_for(session_id)
|
|
107
|
+
else
|
|
108
|
+
remove_all_active_sessions
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
98
112
|
def remove_inactive_sessions
|
|
99
113
|
if cond = inactive_session_cond
|
|
100
114
|
active_sessions_ds.where(cond).delete
|
|
@@ -136,6 +136,7 @@ module Rodauth
|
|
|
136
136
|
|
|
137
137
|
attr_reader :scope
|
|
138
138
|
attr_reader :account
|
|
139
|
+
attr_reader :current_route
|
|
139
140
|
|
|
140
141
|
def initialize(scope)
|
|
141
142
|
@scope = scope
|
|
@@ -428,7 +429,7 @@ module Rodauth
|
|
|
428
429
|
require 'bcrypt' if require_bcrypt?
|
|
429
430
|
db.extension :date_arithmetic if use_date_arithmetic?
|
|
430
431
|
|
|
431
|
-
if convert_token_id_to_integer
|
|
432
|
+
if method(:convert_token_id_to_integer?).owner == Rodauth::Base && (db rescue false) && db.table_exists?(accounts_table) && db.schema(accounts_table).find{|col, v| break v[:type] == :integer if col == account_id_column}
|
|
432
433
|
self.class.send(:define_method, :convert_token_id_to_integer?){true}
|
|
433
434
|
end
|
|
434
435
|
|
|
@@ -711,7 +712,7 @@ module Rodauth
|
|
|
711
712
|
# note that only the salt is returned.
|
|
712
713
|
def get_password_hash
|
|
713
714
|
if account_password_hash_column
|
|
714
|
-
account
|
|
715
|
+
account[account_password_hash_column] if account!
|
|
715
716
|
elsif use_database_authentication_functions?
|
|
716
717
|
db.get(Sequel.function(function_name(:rodauth_get_salt), account ? account_id : session_value))
|
|
717
718
|
else
|
|
@@ -77,14 +77,12 @@ module Rodauth
|
|
|
77
77
|
redirect(r.path)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
if key = session[email_auth_session_key]
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
redirect require_login_redirect
|
|
87
|
-
end
|
|
80
|
+
if (key = session[email_auth_session_key]) && account_from_email_auth_key(key)
|
|
81
|
+
email_auth_view
|
|
82
|
+
else
|
|
83
|
+
remove_session_value(email_auth_session_key)
|
|
84
|
+
set_redirect_error_flash no_matching_email_auth_key_error_flash
|
|
85
|
+
redirect require_login_redirect
|
|
88
86
|
end
|
|
89
87
|
end
|
|
90
88
|
|
|
@@ -104,14 +104,12 @@ module Rodauth
|
|
|
104
104
|
redirect(r.path)
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
-
if key = session[unlock_account_session_key]
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
redirect require_login_redirect
|
|
114
|
-
end
|
|
107
|
+
if (key = session[unlock_account_session_key]) && account_from_unlock_key(key)
|
|
108
|
+
unlock_account_view
|
|
109
|
+
else
|
|
110
|
+
remove_session_value(unlock_account_session_key)
|
|
111
|
+
set_redirect_error_flash no_matching_unlock_account_key_error_flash
|
|
112
|
+
redirect require_login_redirect
|
|
115
113
|
end
|
|
116
114
|
end
|
|
117
115
|
|
|
@@ -109,14 +109,12 @@ module Rodauth
|
|
|
109
109
|
redirect(r.path)
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
-
if key = session[reset_password_session_key]
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
redirect require_login_redirect
|
|
119
|
-
end
|
|
112
|
+
if (key = session[reset_password_session_key]) && account_from_reset_password_key(key)
|
|
113
|
+
reset_password_view
|
|
114
|
+
else
|
|
115
|
+
remove_session_value(reset_password_session_key)
|
|
116
|
+
set_redirect_error_flash no_matching_reset_password_key_error_flash
|
|
117
|
+
redirect require_login_redirect
|
|
120
118
|
end
|
|
121
119
|
end
|
|
122
120
|
|
|
@@ -76,6 +76,7 @@ module Rodauth
|
|
|
76
76
|
auth_value_method :sms_code_param, 'sms-code'
|
|
77
77
|
auth_value_method :sms_codes_table, :account_sms_codes
|
|
78
78
|
auth_value_method :sms_confirm_code_length, 12
|
|
79
|
+
auth_value_method :sms_confirm_deadline, 86400
|
|
79
80
|
auth_value_method :sms_failure_limit, 5
|
|
80
81
|
auth_value_method :sms_failures_column, :num_failures
|
|
81
82
|
auth_value_method :sms_id_column, :id
|
|
@@ -112,6 +113,7 @@ module Rodauth
|
|
|
112
113
|
:sms_new_confirm_code,
|
|
113
114
|
:sms_normalize_phone,
|
|
114
115
|
:sms_record_failure,
|
|
116
|
+
:sms_remove_expired_confirm_code,
|
|
115
117
|
:sms_remove_failures,
|
|
116
118
|
:sms_send,
|
|
117
119
|
:sms_set_code,
|
|
@@ -196,6 +198,7 @@ module Rodauth
|
|
|
196
198
|
require_two_factor_setup
|
|
197
199
|
require_two_factor_authenticated
|
|
198
200
|
end
|
|
201
|
+
sms_remove_expired_confirm_code
|
|
199
202
|
require_sms_not_setup
|
|
200
203
|
|
|
201
204
|
if sms_needs_confirmation?
|
|
@@ -244,6 +247,7 @@ module Rodauth
|
|
|
244
247
|
require_two_factor_setup
|
|
245
248
|
require_two_factor_authenticated
|
|
246
249
|
end
|
|
250
|
+
sms_remove_expired_confirm_code
|
|
247
251
|
require_sms_not_setup
|
|
248
252
|
before_sms_confirm_route
|
|
249
253
|
|
|
@@ -362,16 +366,17 @@ module Rodauth
|
|
|
362
366
|
def sms_setup(phone_number)
|
|
363
367
|
# Cannot handle uniqueness violation here, as the phone number given may not match the
|
|
364
368
|
# one in the table.
|
|
365
|
-
sms_ds.insert(sms_id_column=>session_value, sms_phone_column=>phone_number)
|
|
369
|
+
sms_ds.insert(sms_id_column=>session_value, sms_phone_column=>phone_number, sms_failures_column => nil)
|
|
366
370
|
remove_instance_variable(:@sms) if instance_variable_defined?(:@sms)
|
|
367
371
|
end
|
|
368
372
|
|
|
369
373
|
def sms_remove_failures
|
|
370
|
-
|
|
374
|
+
return if sms_needs_confirmation?
|
|
375
|
+
update_hash_ds(sms, sms_ds.exclude(sms_failures_column => nil), sms_failures_column => 0, sms_code_column => nil)
|
|
371
376
|
end
|
|
372
377
|
|
|
373
378
|
def sms_confirm
|
|
374
|
-
|
|
379
|
+
update_hash_ds(sms, sms_ds.where(sms_failures_column => nil), sms_failures_column => 0, sms_code_column => nil)
|
|
375
380
|
super if defined?(super)
|
|
376
381
|
end
|
|
377
382
|
|
|
@@ -407,6 +412,13 @@ module Rodauth
|
|
|
407
412
|
update_sms(sms_code_column=>code, sms_issued_at_column=>Sequel::CURRENT_TIMESTAMP)
|
|
408
413
|
end
|
|
409
414
|
|
|
415
|
+
def sms_remove_expired_confirm_code
|
|
416
|
+
db[sms_codes_table].
|
|
417
|
+
where(sms_id_column=>session_value, sms_failures_column => nil).
|
|
418
|
+
where(Sequel[sms_issued_at_column] < Sequel.date_sub(Sequel::CURRENT_TIMESTAMP, seconds: sms_confirm_deadline)).
|
|
419
|
+
delete
|
|
420
|
+
end
|
|
421
|
+
|
|
410
422
|
def sms_record_failure
|
|
411
423
|
update_sms(sms_failures_column=>Sequel.expr(sms_failures_column)+1)
|
|
412
424
|
sms[sms_failures_column] = sms_ds.get(sms_failures_column)
|
|
@@ -516,5 +528,9 @@ module Rodauth
|
|
|
516
528
|
def sms_ds
|
|
517
529
|
db[sms_codes_table].where(sms_id_column=>session_value)
|
|
518
530
|
end
|
|
531
|
+
|
|
532
|
+
def use_date_arithmetic?
|
|
533
|
+
true
|
|
534
|
+
end
|
|
519
535
|
end
|
|
520
536
|
end
|
|
@@ -102,14 +102,12 @@ module Rodauth
|
|
|
102
102
|
redirect(r.path)
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
-
if key = session[verify_account_session_key]
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
redirect require_login_redirect
|
|
112
|
-
end
|
|
105
|
+
if (key = session[verify_account_session_key]) && account_from_verify_account_key(key)
|
|
106
|
+
verify_account_view
|
|
107
|
+
else
|
|
108
|
+
remove_session_value(verify_account_session_key)
|
|
109
|
+
set_redirect_error_flash no_matching_verify_account_key_error_flash
|
|
110
|
+
redirect require_login_redirect
|
|
113
111
|
end
|
|
114
112
|
end
|
|
115
113
|
|
|
@@ -62,14 +62,12 @@ module Rodauth
|
|
|
62
62
|
redirect(r.path)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
if key = session[verify_login_change_session_key]
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
redirect require_login_redirect
|
|
72
|
-
end
|
|
65
|
+
if (key = session[verify_login_change_session_key]) && account_from_verify_login_change_key(key)
|
|
66
|
+
verify_login_change_view
|
|
67
|
+
else
|
|
68
|
+
remove_session_value(verify_login_change_session_key)
|
|
69
|
+
set_redirect_error_flash no_matching_verify_login_change_key_error_flash
|
|
70
|
+
redirect require_login_redirect
|
|
73
71
|
end
|
|
74
72
|
end
|
|
75
73
|
|
|
@@ -302,22 +302,17 @@ module Rodauth
|
|
|
302
302
|
def new_webauthn_credential
|
|
303
303
|
WebAuthn::Credential.options_for_create(
|
|
304
304
|
:timeout => webauthn_setup_timeout,
|
|
305
|
-
:rp => {:name=>webauthn_rp_name, :id=>webauthn_rp_id},
|
|
306
305
|
:user => {:id=>account_webauthn_user_id, :name=>webauthn_user_name},
|
|
307
306
|
:authenticator_selection => webauthn_authenticator_selection,
|
|
308
307
|
:attestation => webauthn_attestation,
|
|
309
308
|
:extensions => webauthn_extensions,
|
|
310
309
|
:exclude => account_webauthn_ids,
|
|
310
|
+
**webauthn_create_relying_party_opts
|
|
311
311
|
)
|
|
312
312
|
end
|
|
313
313
|
|
|
314
314
|
def valid_new_webauthn_credential?(webauthn_credential)
|
|
315
|
-
|
|
316
|
-
origin = webauthn_origin
|
|
317
|
-
webauthn_credential.response.define_singleton_method(:verify) do |expected_challenge, expected_origin = nil, **kw|
|
|
318
|
-
super(expected_challenge, expected_origin || origin, **kw)
|
|
319
|
-
end
|
|
320
|
-
|
|
315
|
+
_override_webauthn_credential_response_verify(webauthn_credential)
|
|
321
316
|
(challenge = param_or_nil(webauthn_setup_challenge_param)) &&
|
|
322
317
|
(hmac = param_or_nil(webauthn_setup_challenge_hmac_param)) &&
|
|
323
318
|
(timing_safe_eql?(compute_hmac(challenge), hmac) || (hmac_secret_rotation? && timing_safe_eql?(compute_old_hmac(challenge), hmac))) &&
|
|
@@ -328,9 +323,9 @@ module Rodauth
|
|
|
328
323
|
WebAuthn::Credential.options_for_get(
|
|
329
324
|
:allow => webauthn_allow,
|
|
330
325
|
:timeout => webauthn_auth_timeout,
|
|
331
|
-
:rp_id => webauthn_rp_id,
|
|
332
326
|
:user_verification => webauthn_user_verification,
|
|
333
327
|
:extensions => webauthn_extensions,
|
|
328
|
+
**webauthn_get_relying_party_opts
|
|
334
329
|
)
|
|
335
330
|
end
|
|
336
331
|
|
|
@@ -368,12 +363,7 @@ module Rodauth
|
|
|
368
363
|
ds = webauthn_keys_ds.where(webauthn_keys_webauthn_id_column => webauthn_credential.id)
|
|
369
364
|
pub_key, sign_count = ds.get([webauthn_keys_public_key_column, webauthn_keys_sign_count_column])
|
|
370
365
|
|
|
371
|
-
|
|
372
|
-
origin = webauthn_origin
|
|
373
|
-
webauthn_credential.response.define_singleton_method(:verify) do |expected_challenge, expected_origin = nil, **kw|
|
|
374
|
-
super(expected_challenge, expected_origin || origin, **kw)
|
|
375
|
-
end
|
|
376
|
-
|
|
366
|
+
_override_webauthn_credential_response_verify(webauthn_credential)
|
|
377
367
|
(challenge = param_or_nil(webauthn_auth_challenge_param)) &&
|
|
378
368
|
(hmac = param_or_nil(webauthn_auth_challenge_hmac_param)) &&
|
|
379
369
|
(timing_safe_eql?(compute_hmac(challenge), hmac) || (hmac_secret_rotation? && timing_safe_eql?(compute_old_hmac(challenge), hmac))) &&
|
|
@@ -419,6 +409,54 @@ module Rodauth
|
|
|
419
409
|
|
|
420
410
|
private
|
|
421
411
|
|
|
412
|
+
if WebAuthn::VERSION >= '3'
|
|
413
|
+
def webauthn_relying_party
|
|
414
|
+
# No need to memoize, only called once per request
|
|
415
|
+
WebAuthn::RelyingParty.new(
|
|
416
|
+
origin: webauthn_origin,
|
|
417
|
+
id: webauthn_rp_id,
|
|
418
|
+
name: webauthn_rp_name,
|
|
419
|
+
)
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def webauthn_create_relying_party_opts
|
|
423
|
+
{ :relying_party => webauthn_relying_party }
|
|
424
|
+
end
|
|
425
|
+
alias webauthn_get_relying_party_opts webauthn_create_relying_party_opts
|
|
426
|
+
|
|
427
|
+
def webauthn_form_submission_call(meth, arg)
|
|
428
|
+
WebAuthn::Credential.public_send(meth, arg, :relying_party => webauthn_relying_party)
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def _override_webauthn_credential_response_verify(webauthn_credential)
|
|
432
|
+
# no need to override
|
|
433
|
+
end
|
|
434
|
+
# :nocov:
|
|
435
|
+
else
|
|
436
|
+
def webauthn_create_relying_party_opts
|
|
437
|
+
{:rp => {:name=>webauthn_rp_name, :id=>webauthn_rp_id}}
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def webauthn_get_relying_party_opts
|
|
441
|
+
{ :rp_id => webauthn_rp_id }
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def webauthn_form_submission_call(meth, arg)
|
|
445
|
+
WebAuthn::Credential.public_send(meth, arg)
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
def _override_webauthn_credential_response_verify(webauthn_credential)
|
|
449
|
+
# Hack around inability to override expected_origin and rp_id
|
|
450
|
+
origin = webauthn_origin
|
|
451
|
+
rp_id = webauthn_rp_id
|
|
452
|
+
webauthn_credential.response.define_singleton_method(:verify) do |expected_challenge, expected_origin = nil, **kw|
|
|
453
|
+
kw[:rp_id] = rp_id
|
|
454
|
+
super(expected_challenge, expected_origin || origin, **kw)
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
# :nocov:
|
|
458
|
+
end
|
|
459
|
+
|
|
422
460
|
def _two_factor_auth_links
|
|
423
461
|
links = super
|
|
424
462
|
links << [10, webauthn_auth_path, webauthn_auth_link_text] if webauthn_setup? && !two_factor_login_type_match?('webauthn')
|
|
@@ -464,7 +502,8 @@ module Rodauth
|
|
|
464
502
|
|
|
465
503
|
def webauthn_auth_credential_from_form_submission
|
|
466
504
|
begin
|
|
467
|
-
webauthn_credential =
|
|
505
|
+
webauthn_credential = webauthn_form_submission_call(:from_get, webauthn_auth_data)
|
|
506
|
+
|
|
468
507
|
unless valid_webauthn_credential_auth?(webauthn_credential)
|
|
469
508
|
throw_error_reason(:invalid_webauthn_auth_param, invalid_key_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message)
|
|
470
509
|
end
|
|
@@ -498,7 +537,8 @@ module Rodauth
|
|
|
498
537
|
end
|
|
499
538
|
|
|
500
539
|
begin
|
|
501
|
-
webauthn_credential =
|
|
540
|
+
webauthn_credential = webauthn_form_submission_call(:from_create, webauthn_setup_data)
|
|
541
|
+
|
|
502
542
|
unless valid_new_webauthn_credential?(webauthn_credential)
|
|
503
543
|
throw_error_reason(:invalid_webauthn_setup_param, invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message)
|
|
504
544
|
end
|
data/lib/rodauth/version.rb
CHANGED
data/lib/rodauth.rb
CHANGED
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.34.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: 2024-03-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: sequel
|
|
@@ -350,6 +350,8 @@ extra_rdoc_files:
|
|
|
350
350
|
- doc/release_notes/2.30.0.txt
|
|
351
351
|
- doc/release_notes/2.31.0.txt
|
|
352
352
|
- doc/release_notes/2.32.0.txt
|
|
353
|
+
- doc/release_notes/2.33.0.txt
|
|
354
|
+
- doc/release_notes/2.34.0.txt
|
|
353
355
|
- doc/release_notes/2.4.0.txt
|
|
354
356
|
- doc/release_notes/2.5.0.txt
|
|
355
357
|
- doc/release_notes/2.6.0.txt
|
|
@@ -470,6 +472,8 @@ files:
|
|
|
470
472
|
- doc/release_notes/2.30.0.txt
|
|
471
473
|
- doc/release_notes/2.31.0.txt
|
|
472
474
|
- doc/release_notes/2.32.0.txt
|
|
475
|
+
- doc/release_notes/2.33.0.txt
|
|
476
|
+
- doc/release_notes/2.34.0.txt
|
|
473
477
|
- doc/release_notes/2.4.0.txt
|
|
474
478
|
- doc/release_notes/2.5.0.txt
|
|
475
479
|
- doc/release_notes/2.6.0.txt
|
|
@@ -630,7 +634,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
630
634
|
- !ruby/object:Gem::Version
|
|
631
635
|
version: '0'
|
|
632
636
|
requirements: []
|
|
633
|
-
rubygems_version: 3.
|
|
637
|
+
rubygems_version: 3.5.3
|
|
634
638
|
signing_key:
|
|
635
639
|
specification_version: 4
|
|
636
640
|
summary: Authentication and Account Management Framework for Rack Applications
|