rodauth 2.43.0 → 2.44.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/lib/rodauth/features/active_sessions.rb +32 -0
- data/lib/rodauth/features/argon2.rb +2 -0
- data/lib/rodauth/features/base.rb +34 -3
- data/lib/rodauth/features/disallow_password_reuse.rb +2 -0
- data/lib/rodauth/features/email_auth.rb +2 -0
- data/lib/rodauth/features/http_basic_auth.rb +8 -3
- data/lib/rodauth/features/internal_request.rb +16 -1
- data/lib/rodauth/features/json.rb +4 -2
- data/lib/rodauth/features/jwt.rb +5 -3
- data/lib/rodauth/features/jwt_refresh.rb +2 -0
- data/lib/rodauth/features/lockout.rb +2 -0
- data/lib/rodauth/features/login.rb +12 -2
- data/lib/rodauth/features/login_password_requirements_base.rb +2 -0
- data/lib/rodauth/features/otp.rb +8 -6
- data/lib/rodauth/features/otp_unlock.rb +2 -0
- data/lib/rodauth/features/password_grace_period.rb +3 -1
- data/lib/rodauth/features/password_pepper.rb +2 -0
- data/lib/rodauth/features/recovery_codes.rb +4 -2
- data/lib/rodauth/features/remember.rb +2 -0
- data/lib/rodauth/features/reset_password.rb +2 -0
- data/lib/rodauth/features/sms_codes.rb +14 -6
- data/lib/rodauth/features/two_factor_base.rb +2 -0
- data/lib/rodauth/features/update_password_hash.rb +2 -0
- data/lib/rodauth/features/verify_account.rb +2 -0
- data/lib/rodauth/features/verify_login_change.rb +2 -0
- data/lib/rodauth/features/webauthn_login.rb +2 -0
- data/lib/rodauth/features/webauthn_verify_account.rb +2 -0
- data/lib/rodauth/version.rb +1 -1
- data/lib/rodauth.rb +79 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 040bf69b63cc893df29a1a4e5c99889f5dc7fcae928c81639be5a38157dc910e
|
|
4
|
+
data.tar.gz: 0f013ee9f86f80379fe575251697fc622f9c0d9ede248e39df67565312edc6eb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a9d5ec9033e65cd7578dad8864eb5fcfb258f7ba4484e949923a3502e2e642a77898a01fa2dbb0947d92c4ce009e9b238d5e11a7243cf7f25ad566e9c38c6d72
|
|
7
|
+
data.tar.gz: 2fb3aafcb91f26560370059512bb074122bb87267c7d50c27aa465a2ede5b0380dec0d0d17cb946121ca83a28716ffad02427bc83ae9c4959c44f5bc82a21bb9
|
|
@@ -37,6 +37,8 @@ module Rodauth
|
|
|
37
37
|
:remove_inactive_sessions,
|
|
38
38
|
)
|
|
39
39
|
|
|
40
|
+
uses_instance_variables(:@active_sessions_key, :@clear_active_sessions_after_two_factor_setup)
|
|
41
|
+
|
|
40
42
|
def currently_active_session?
|
|
41
43
|
return false unless session_id = session[session_id_session_key]
|
|
42
44
|
|
|
@@ -148,6 +150,21 @@ module Rodauth
|
|
|
148
150
|
remove_all_active_sessions
|
|
149
151
|
end
|
|
150
152
|
|
|
153
|
+
def after_otp_setup
|
|
154
|
+
super if defined?(super)
|
|
155
|
+
remove_all_active_sessions_except_current if @clear_active_sessions_after_two_factor_setup
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def after_sms_confirm
|
|
159
|
+
super if defined?(super)
|
|
160
|
+
remove_all_active_sessions_except_current if @clear_active_sessions_after_two_factor_setup
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def after_webauthn_setup
|
|
164
|
+
super if defined?(super)
|
|
165
|
+
remove_all_active_sessions_except_current if @clear_active_sessions_after_two_factor_setup
|
|
166
|
+
end
|
|
167
|
+
|
|
151
168
|
def before_logout
|
|
152
169
|
if param_or_nil(global_logout_param)
|
|
153
170
|
remove_remember_key(session_value) if respond_to?(:remove_remember_key)
|
|
@@ -158,6 +175,21 @@ module Rodauth
|
|
|
158
175
|
super
|
|
159
176
|
end
|
|
160
177
|
|
|
178
|
+
def before_otp_setup
|
|
179
|
+
@clear_active_sessions_after_two_factor_setup = !two_factor_authentication_setup?
|
|
180
|
+
super if defined?(super)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def before_sms_confirm
|
|
184
|
+
@clear_active_sessions_after_two_factor_setup = !two_factor_authentication_setup?
|
|
185
|
+
super if defined?(super)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def before_webauthn_setup
|
|
189
|
+
@clear_active_sessions_after_two_factor_setup = !two_factor_authentication_setup?
|
|
190
|
+
super if defined?(super)
|
|
191
|
+
end
|
|
192
|
+
|
|
161
193
|
attr_reader :active_sessions_key
|
|
162
194
|
|
|
163
195
|
def generate_active_sessions_key
|
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
# frozen-string-literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require
|
|
3
|
+
begin
|
|
4
|
+
require "rack/version"
|
|
5
|
+
# :nocov:
|
|
6
|
+
rescue LoadError
|
|
7
|
+
require "rack"
|
|
8
|
+
else
|
|
9
|
+
if Rack.release >= '3'
|
|
10
|
+
require "rack/request"
|
|
11
|
+
require "rack/utils"
|
|
12
|
+
else
|
|
13
|
+
require "rack"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
# :nocov:
|
|
5
17
|
|
|
6
18
|
module Rodauth
|
|
7
19
|
Feature.define(:base, :Base) do
|
|
8
20
|
after 'login'
|
|
21
|
+
after 'no_matching_login'
|
|
9
22
|
after 'login_failure'
|
|
10
23
|
before 'login'
|
|
11
24
|
before 'login_attempt'
|
|
@@ -137,14 +150,29 @@ module Rodauth
|
|
|
137
150
|
def auth_class_eval(&block)
|
|
138
151
|
auth.class_eval(&block)
|
|
139
152
|
end
|
|
153
|
+
|
|
154
|
+
def uses_instance_variables(*ivs)
|
|
155
|
+
auth.define_singleton_method(:instance_variables_used) do
|
|
156
|
+
super() + ivs
|
|
157
|
+
end
|
|
158
|
+
end
|
|
140
159
|
end
|
|
141
160
|
|
|
161
|
+
uses_instance_variables(
|
|
162
|
+
:@account,
|
|
163
|
+
:@current_route,
|
|
164
|
+
:@field_errors,
|
|
165
|
+
:@password_field_autocomplete_value,
|
|
166
|
+
:@has_password
|
|
167
|
+
)
|
|
168
|
+
|
|
142
169
|
attr_reader :scope
|
|
143
170
|
attr_reader :account
|
|
144
171
|
attr_reader :current_route
|
|
145
172
|
|
|
146
173
|
def initialize(scope)
|
|
147
174
|
@scope = scope
|
|
175
|
+
_initialize_instance_variables
|
|
148
176
|
end
|
|
149
177
|
|
|
150
178
|
def features
|
|
@@ -549,13 +577,16 @@ module Rodauth
|
|
|
549
577
|
end
|
|
550
578
|
|
|
551
579
|
def has_password?
|
|
552
|
-
return @has_password
|
|
580
|
+
return @has_password unless @has_password.nil?
|
|
553
581
|
return false unless account || session_value
|
|
554
582
|
@has_password = !!get_password_hash
|
|
555
583
|
end
|
|
556
584
|
|
|
557
585
|
private
|
|
558
586
|
|
|
587
|
+
def _initialize_instance_variables
|
|
588
|
+
end
|
|
589
|
+
|
|
559
590
|
def _around_rodauth
|
|
560
591
|
yield
|
|
561
592
|
end
|
|
@@ -5,10 +5,12 @@ module Rodauth
|
|
|
5
5
|
auth_value_method :http_basic_auth_realm, "protected"
|
|
6
6
|
auth_value_method :require_http_basic_auth?, false
|
|
7
7
|
|
|
8
|
+
uses_instance_variables(:@checked_http_basic_auth)
|
|
9
|
+
|
|
8
10
|
def logged_in?
|
|
9
11
|
ret = super
|
|
10
12
|
|
|
11
|
-
if !ret &&
|
|
13
|
+
if !ret && @checked_http_basic_auth.nil?
|
|
12
14
|
http_basic_auth
|
|
13
15
|
ret = super
|
|
14
16
|
end
|
|
@@ -32,9 +34,11 @@ module Rodauth
|
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
def http_basic_auth
|
|
35
|
-
|
|
37
|
+
unless @checked_http_basic_auth.nil?
|
|
38
|
+
return (@checked_http_basic_auth ? true : nil)
|
|
39
|
+
end
|
|
36
40
|
|
|
37
|
-
@checked_http_basic_auth =
|
|
41
|
+
@checked_http_basic_auth = false
|
|
38
42
|
return unless token = ((v = request.env['HTTP_AUTHORIZATION']) && v[/\A *Basic (.*)\Z/, 1])
|
|
39
43
|
|
|
40
44
|
username, password = token.unpack("m*").first.split(/:/, 2)
|
|
@@ -42,6 +46,7 @@ module Rodauth
|
|
|
42
46
|
|
|
43
47
|
catch_error do
|
|
44
48
|
unless account_from_login(username)
|
|
49
|
+
after_no_matching_login
|
|
45
50
|
throw_basic_auth_error(login_param, no_matching_login_message)
|
|
46
51
|
end
|
|
47
52
|
|
|
@@ -187,6 +187,7 @@ module Rodauth
|
|
|
187
187
|
end
|
|
188
188
|
|
|
189
189
|
def _set_internal_request_return_value(value)
|
|
190
|
+
@internal_request_return_value_set = true
|
|
190
191
|
@internal_request_return_value = value
|
|
191
192
|
end
|
|
192
193
|
|
|
@@ -219,7 +220,7 @@ module Rodauth
|
|
|
219
220
|
|
|
220
221
|
def _handle_internal_request_eval(_)
|
|
221
222
|
v = instance_eval(&internal_request_block)
|
|
222
|
-
_set_internal_request_return_value(v) unless
|
|
223
|
+
_set_internal_request_return_value(v) unless @internal_request_return_value_set
|
|
223
224
|
end
|
|
224
225
|
|
|
225
226
|
def _handle_account_id_for_login(_)
|
|
@@ -304,6 +305,19 @@ module Rodauth
|
|
|
304
305
|
end
|
|
305
306
|
|
|
306
307
|
module InternalRequestClassMethods
|
|
308
|
+
def instance_variables_used
|
|
309
|
+
super + [
|
|
310
|
+
:@session,
|
|
311
|
+
:@params,
|
|
312
|
+
:@flash,
|
|
313
|
+
:@internal_request_block,
|
|
314
|
+
:@internal_request_return_value,
|
|
315
|
+
:@internal_request_return_value_set,
|
|
316
|
+
:@error_reason,
|
|
317
|
+
:@return_false_on_error
|
|
318
|
+
]
|
|
319
|
+
end
|
|
320
|
+
|
|
307
321
|
def internal_request(route, opts={}, &block)
|
|
308
322
|
opts = opts.dup
|
|
309
323
|
|
|
@@ -404,6 +418,7 @@ module Rodauth
|
|
|
404
418
|
|
|
405
419
|
internal_class.send(:extend, InternalRequestClassMethods)
|
|
406
420
|
internal_class.send(:include, InternalRequestMethods)
|
|
421
|
+
internal_class.send(:make_shape_friendly)
|
|
407
422
|
internal_class.allocate.post_configure
|
|
408
423
|
|
|
409
424
|
([:base] + internal_class.features).each do |feature_name|
|
|
@@ -27,6 +27,8 @@ module Rodauth
|
|
|
27
27
|
|
|
28
28
|
auth_private_methods :json_response_body
|
|
29
29
|
|
|
30
|
+
uses_instance_variables(:@json_request)
|
|
31
|
+
|
|
30
32
|
def set_field_error(field, message)
|
|
31
33
|
return super unless use_json?
|
|
32
34
|
json_response[json_response_field_error_key] = [field, message]
|
|
@@ -53,8 +55,8 @@ module Rodauth
|
|
|
53
55
|
end
|
|
54
56
|
|
|
55
57
|
def json_request?
|
|
56
|
-
return @json_request
|
|
57
|
-
@json_request = request.content_type
|
|
58
|
+
return @json_request unless @json_request.nil?
|
|
59
|
+
@json_request = !(request.content_type !~ json_request_content_type_regexp)
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
def use_json?
|
data/lib/rodauth/features/jwt.rb
CHANGED
|
@@ -30,8 +30,10 @@ module Rodauth
|
|
|
30
30
|
|
|
31
31
|
def_deprecated_alias :json_check_accept?, :jwt_check_accept?
|
|
32
32
|
|
|
33
|
+
uses_instance_variables(:@session, :@jwt_token, :@jwt_payload)
|
|
34
|
+
|
|
33
35
|
def session
|
|
34
|
-
return @session if
|
|
36
|
+
return @session if @session
|
|
35
37
|
return super unless use_jwt?
|
|
36
38
|
|
|
37
39
|
s = {}
|
|
@@ -76,7 +78,7 @@ module Rodauth
|
|
|
76
78
|
end
|
|
77
79
|
|
|
78
80
|
def jwt_token
|
|
79
|
-
return @jwt_token if
|
|
81
|
+
return @jwt_token if @jwt_token
|
|
80
82
|
|
|
81
83
|
if (v = request.env['HTTP_AUTHORIZATION']) && v !~ jwt_authorization_ignore
|
|
82
84
|
@jwt_token = v.sub(jwt_authorization_remove, '')
|
|
@@ -120,7 +122,7 @@ module Rodauth
|
|
|
120
122
|
end
|
|
121
123
|
|
|
122
124
|
def jwt_payload
|
|
123
|
-
return @jwt_payload
|
|
125
|
+
return @jwt_payload unless @jwt_payload.nil?
|
|
124
126
|
@jwt_payload = JWT.decode(jwt_token, _jwt_decode_secrets, true, _jwt_decode_opts.merge(:algorithm=>jwt_algorithm))[0]
|
|
125
127
|
rescue JWT::DecodeError => e
|
|
126
128
|
rescue_jwt_payload(e)
|
|
@@ -61,6 +61,8 @@ module Rodauth
|
|
|
61
61
|
)
|
|
62
62
|
auth_private_methods :account_from_unlock_key
|
|
63
63
|
|
|
64
|
+
uses_instance_variables(:@unlock_account_key_value)
|
|
65
|
+
|
|
64
66
|
internal_request_method(:lock_account)
|
|
65
67
|
internal_request_method(:unlock_account_request)
|
|
66
68
|
internal_request_method(:unlock_account)
|
|
@@ -20,8 +20,8 @@ module Rodauth
|
|
|
20
20
|
|
|
21
21
|
session_key :login_redirect_session_key, :login_redirect
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
cached_auth_method :multi_phase_login_forms
|
|
24
|
+
cached_auth_method :login_form_footer
|
|
25
25
|
|
|
26
26
|
auth_value_methods :login_return_to_requested_location_path
|
|
27
27
|
|
|
@@ -30,6 +30,15 @@ module Rodauth
|
|
|
30
30
|
:login_response
|
|
31
31
|
)
|
|
32
32
|
|
|
33
|
+
uses_instance_variables(
|
|
34
|
+
:@login_form_footer,
|
|
35
|
+
:@login_form_footer_links,
|
|
36
|
+
:@login_form_header,
|
|
37
|
+
:@multi_phase_login_forms,
|
|
38
|
+
:@saved_login_redirect,
|
|
39
|
+
:@valid_login_entered
|
|
40
|
+
)
|
|
41
|
+
|
|
33
42
|
internal_request_method
|
|
34
43
|
internal_request_method :valid_login_and_password?
|
|
35
44
|
|
|
@@ -47,6 +56,7 @@ module Rodauth
|
|
|
47
56
|
|
|
48
57
|
catch_error do
|
|
49
58
|
unless account_from_login(login_param_value)
|
|
59
|
+
after_no_matching_login
|
|
50
60
|
throw_error_reason(:no_matching_login, no_matching_login_error_status, login_param, no_matching_login_message)
|
|
51
61
|
end
|
|
52
62
|
|
data/lib/rodauth/features/otp.rb
CHANGED
|
@@ -68,8 +68,8 @@ module Rodauth
|
|
|
68
68
|
auth_value_method :otp_setup_raw_param, 'otp_raw_secret'
|
|
69
69
|
translatable_method :otp_auth_form_footer, ''
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
cached_auth_method :otp_key
|
|
72
|
+
cached_auth_method :otp
|
|
73
73
|
private :otp
|
|
74
74
|
|
|
75
75
|
auth_value_methods(
|
|
@@ -100,6 +100,8 @@ module Rodauth
|
|
|
100
100
|
:otp_valid_code_for_old_secret
|
|
101
101
|
)
|
|
102
102
|
|
|
103
|
+
uses_instance_variables(:@otp, :@otp_key, :@otp_user_key, :@otp_tmp_key)
|
|
104
|
+
|
|
103
105
|
internal_request_method :otp_setup_params
|
|
104
106
|
internal_request_method :otp_setup
|
|
105
107
|
internal_request_method :otp_auth
|
|
@@ -245,7 +247,7 @@ module Rodauth
|
|
|
245
247
|
end
|
|
246
248
|
|
|
247
249
|
def otp_exists?
|
|
248
|
-
|
|
250
|
+
!!otp_key
|
|
249
251
|
end
|
|
250
252
|
|
|
251
253
|
def otp_valid_code?(ot_pass)
|
|
@@ -277,7 +279,7 @@ module Rodauth
|
|
|
277
279
|
|
|
278
280
|
def otp_remove
|
|
279
281
|
otp_key_ds.delete
|
|
280
|
-
@otp_key =
|
|
282
|
+
@otp_key = false
|
|
281
283
|
end
|
|
282
284
|
|
|
283
285
|
def otp_add_key
|
|
@@ -368,7 +370,7 @@ module Rodauth
|
|
|
368
370
|
end
|
|
369
371
|
|
|
370
372
|
def clear_cached_otp
|
|
371
|
-
|
|
373
|
+
@otp = nil
|
|
372
374
|
end
|
|
373
375
|
|
|
374
376
|
def otp_tmp_key(secret)
|
|
@@ -436,7 +438,7 @@ module Rodauth
|
|
|
436
438
|
|
|
437
439
|
def _otp_key
|
|
438
440
|
@otp_user_key = nil
|
|
439
|
-
otp_key_ds.get(otp_keys_column)
|
|
441
|
+
otp_key_ds.get(otp_keys_column) || false
|
|
440
442
|
end
|
|
441
443
|
|
|
442
444
|
def _otp_for_key(key)
|
|
@@ -7,6 +7,8 @@ module Rodauth
|
|
|
7
7
|
|
|
8
8
|
auth_methods :password_recently_entered?
|
|
9
9
|
|
|
10
|
+
uses_instance_variables(:@last_password_entry)
|
|
11
|
+
|
|
10
12
|
def modifications_require_password?
|
|
11
13
|
return false unless super
|
|
12
14
|
!password_recently_entered?
|
|
@@ -26,7 +28,7 @@ module Rodauth
|
|
|
26
28
|
|
|
27
29
|
def update_session
|
|
28
30
|
super
|
|
29
|
-
set_session_value(last_password_entry_session_key, @last_password_entry) if
|
|
31
|
+
set_session_value(last_password_entry_session_key, @last_password_entry) if @last_password_entry
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
private
|
|
@@ -8,6 +8,8 @@ module Rodauth
|
|
|
8
8
|
auth_value_method :previous_password_peppers, [""]
|
|
9
9
|
auth_value_method :password_pepper_update?, true
|
|
10
10
|
|
|
11
|
+
uses_instance_variables(:@previous_pepper_matched)
|
|
12
|
+
|
|
11
13
|
def password_match?(password)
|
|
12
14
|
if (result = super) && @previous_pepper_matched && password_pepper_update?
|
|
13
15
|
set_password(password)
|
|
@@ -46,7 +46,7 @@ module Rodauth
|
|
|
46
46
|
translatable_method :recovery_auth_link_text, "Authenticate Using Recovery Code"
|
|
47
47
|
translatable_method :recovery_codes_link_text, "View Authentication Recovery Codes"
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
cached_auth_method :recovery_codes
|
|
50
50
|
|
|
51
51
|
auth_value_methods(
|
|
52
52
|
:recovery_codes_primary?
|
|
@@ -60,6 +60,8 @@ module Rodauth
|
|
|
60
60
|
:recovery_codes_available?,
|
|
61
61
|
)
|
|
62
62
|
|
|
63
|
+
uses_instance_variables(:@recovery_codes, :@recovery_codes_button)
|
|
64
|
+
|
|
63
65
|
internal_request_method :recovery_codes
|
|
64
66
|
internal_request_method :recovery_auth
|
|
65
67
|
internal_request_method :valid_recovery_auth?
|
|
@@ -181,7 +183,7 @@ module Rodauth
|
|
|
181
183
|
add_recovery_code
|
|
182
184
|
end
|
|
183
185
|
end
|
|
184
|
-
|
|
186
|
+
@recovery_codes = nil
|
|
185
187
|
end
|
|
186
188
|
|
|
187
189
|
def add_recovery_code
|
|
@@ -89,8 +89,6 @@ module Rodauth
|
|
|
89
89
|
auth_value_method :sms_phone_min_length, 7
|
|
90
90
|
auth_value_method :sms_phone_param, 'sms-phone'
|
|
91
91
|
|
|
92
|
-
auth_cached_method :sms
|
|
93
|
-
|
|
94
92
|
auth_value_methods(
|
|
95
93
|
:sms_codes_primary?,
|
|
96
94
|
:sms_needs_confirmation_notice_flash,
|
|
@@ -98,6 +96,7 @@ module Rodauth
|
|
|
98
96
|
)
|
|
99
97
|
|
|
100
98
|
auth_methods(
|
|
99
|
+
:sms,
|
|
101
100
|
:sms_auth_message,
|
|
102
101
|
:sms_available?,
|
|
103
102
|
:sms_code_issued_at,
|
|
@@ -122,6 +121,8 @@ module Rodauth
|
|
|
122
121
|
:sms_valid_phone?
|
|
123
122
|
)
|
|
124
123
|
|
|
124
|
+
uses_instance_variables(:@sms)
|
|
125
|
+
|
|
125
126
|
internal_request_method :sms_setup
|
|
126
127
|
internal_request_method :sms_confirm
|
|
127
128
|
internal_request_method :sms_request
|
|
@@ -356,7 +357,7 @@ module Rodauth
|
|
|
356
357
|
|
|
357
358
|
def sms_disable
|
|
358
359
|
sms_ds.delete
|
|
359
|
-
@sms =
|
|
360
|
+
@sms = false
|
|
360
361
|
end
|
|
361
362
|
|
|
362
363
|
def sms_confirm_failure
|
|
@@ -367,7 +368,7 @@ module Rodauth
|
|
|
367
368
|
# Cannot handle uniqueness violation here, as the phone number given may not match the
|
|
368
369
|
# one in the table.
|
|
369
370
|
sms_ds.insert(sms_id_column=>session_value, sms_phone_column=>phone_number, sms_failures_column => nil)
|
|
370
|
-
|
|
371
|
+
@sms = nil
|
|
371
372
|
end
|
|
372
373
|
|
|
373
374
|
def sms_remove_failures
|
|
@@ -521,8 +522,15 @@ module Rodauth
|
|
|
521
522
|
update_hash_ds(sms, sms_ds, values)
|
|
522
523
|
end
|
|
523
524
|
|
|
524
|
-
def
|
|
525
|
-
|
|
525
|
+
def sms
|
|
526
|
+
case @sms
|
|
527
|
+
when nil
|
|
528
|
+
(@sms = sms_ds.first || false) || nil
|
|
529
|
+
when false
|
|
530
|
+
nil
|
|
531
|
+
else
|
|
532
|
+
@sms
|
|
533
|
+
end
|
|
526
534
|
end
|
|
527
535
|
|
|
528
536
|
def sms_ds
|
|
@@ -62,6 +62,8 @@ module Rodauth
|
|
|
62
62
|
:two_factor_remove_links
|
|
63
63
|
)
|
|
64
64
|
|
|
65
|
+
uses_instance_variables(:@two_factor_auth_links, :@two_factor_setup_links, :@two_factor_remove_links)
|
|
66
|
+
|
|
65
67
|
internal_request_method :two_factor_disable
|
|
66
68
|
|
|
67
69
|
route(:two_factor_manage, 'multifactor-manage') do |r|
|
|
@@ -4,6 +4,8 @@ module Rodauth
|
|
|
4
4
|
Feature.define(:update_password_hash, :UpdatePasswordHash) do
|
|
5
5
|
depends :login_password_requirements_base
|
|
6
6
|
|
|
7
|
+
uses_instance_variables(:@current_password_hash_cost, :@update_password_hash)
|
|
8
|
+
|
|
7
9
|
def password_match?(password)
|
|
8
10
|
if (result = super) && update_password_hash?
|
|
9
11
|
@update_password_hash = false
|
data/lib/rodauth/version.rb
CHANGED
data/lib/rodauth.rb
CHANGED
|
@@ -63,6 +63,7 @@ module Rodauth
|
|
|
63
63
|
end
|
|
64
64
|
auth_class.class_eval{@configuration_name = opts[:name] unless defined?(@configuration_name)}
|
|
65
65
|
auth_class.configure(&block) if block
|
|
66
|
+
auth_class.send(:make_shape_friendly)
|
|
66
67
|
auth_class.allocate.post_configure if auth_class.method_defined?(:post_configure)
|
|
67
68
|
end
|
|
68
69
|
|
|
@@ -125,6 +126,7 @@ module Rodauth
|
|
|
125
126
|
attr_accessor :routes
|
|
126
127
|
attr_accessor :configuration
|
|
127
128
|
attr_reader :internal_request_methods
|
|
129
|
+
attr_reader :instance_variables_used
|
|
128
130
|
|
|
129
131
|
def route(name=feature_name, default=name.to_s.tr('_', '-'), &block)
|
|
130
132
|
route_meth = :"#{name}_route"
|
|
@@ -175,6 +177,10 @@ module Rodauth
|
|
|
175
177
|
(@internal_request_methods ||= []) << name
|
|
176
178
|
end
|
|
177
179
|
|
|
180
|
+
def uses_instance_variables(*ivs)
|
|
181
|
+
@instance_variables_used = ivs.freeze
|
|
182
|
+
end
|
|
183
|
+
|
|
178
184
|
def configuration_module_eval(&block)
|
|
179
185
|
configuration.module_eval(&block)
|
|
180
186
|
end
|
|
@@ -305,7 +311,24 @@ module Rodauth
|
|
|
305
311
|
auth_value_methods(meth)
|
|
306
312
|
end
|
|
307
313
|
|
|
308
|
-
|
|
314
|
+
# Auth caching method that treats a nil instance variable as
|
|
315
|
+
# not being cached. If nil is a valid value for the instance
|
|
316
|
+
# variable, do not use this method, use a regular auth_method
|
|
317
|
+
# and handle caching manually.
|
|
318
|
+
def cached_auth_method(meth, iv=:"@#{meth}")
|
|
319
|
+
umeth = :"_#{meth}"
|
|
320
|
+
define_method(meth) do
|
|
321
|
+
v = instance_variable_get(iv)
|
|
322
|
+
v.nil? ? instance_variable_set(iv, send(umeth)) : v
|
|
323
|
+
end
|
|
324
|
+
alias_method(meth, meth)
|
|
325
|
+
auth_private_methods(meth)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# :nocov:
|
|
329
|
+
def auth_cached_method(meth, iv=:"@#{meth}") # :nodoc:
|
|
330
|
+
# Non-shape friendly historical method.
|
|
331
|
+
# RODAUTH3: Remove
|
|
309
332
|
umeth = :"_#{meth}"
|
|
310
333
|
define_method(meth) do
|
|
311
334
|
if instance_variable_defined?(iv)
|
|
@@ -317,6 +340,7 @@ module Rodauth
|
|
|
317
340
|
alias_method(meth, meth)
|
|
318
341
|
auth_private_methods(meth)
|
|
319
342
|
end
|
|
343
|
+
# :nocov:
|
|
320
344
|
|
|
321
345
|
[:notice_flash, :error_flash, :button].each do |meth|
|
|
322
346
|
define_method(meth) do |v, name=feature_name|
|
|
@@ -376,6 +400,60 @@ module Rodauth
|
|
|
376
400
|
attr_accessor :route_hash
|
|
377
401
|
attr_reader :configuration_name
|
|
378
402
|
attr_reader :configuration
|
|
403
|
+
|
|
404
|
+
private
|
|
405
|
+
|
|
406
|
+
if RUBY_VERSION >= "3.2" && defined?(RubyVM::YJIT.enable)
|
|
407
|
+
# Use a shape-friendly object on Ruby 3.2 if YJIT is available
|
|
408
|
+
# with the assumption that it will be enabled later in any situation
|
|
409
|
+
# desiring high performance.
|
|
410
|
+
def make_shape_friendly
|
|
411
|
+
ivs = instance_variables_used
|
|
412
|
+
|
|
413
|
+
unless ivs.empty?
|
|
414
|
+
ivs.uniq!
|
|
415
|
+
ivs = ivs.reverse.join(" = ")
|
|
416
|
+
method_content = "#{ivs} = nil"
|
|
417
|
+
class_eval(<<-RUBY, __FILE__, __LINE__+1)
|
|
418
|
+
private def _initialize_instance_variables
|
|
419
|
+
#{method_content}
|
|
420
|
+
end
|
|
421
|
+
alias _initialize_instance_variables _initialize_instance_variables
|
|
422
|
+
RUBY
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
nil
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
def instance_variables_used
|
|
429
|
+
ivs = []
|
|
430
|
+
features = []
|
|
431
|
+
|
|
432
|
+
# Try to ensure that instance variable order follows feature enablement order
|
|
433
|
+
ancestors.each do |mod|
|
|
434
|
+
features << mod if mod.is_a?(Feature)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
features.reverse_each do |mod|
|
|
438
|
+
if (feature_ivs = mod.instance_variables_used)
|
|
439
|
+
feature_ivs.each do |iv|
|
|
440
|
+
unless iv.match?(/\A@[a-z_][a-z0-9_]*\z/)
|
|
441
|
+
raise ConfigurationError, "invalid model instance variable used"
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
ivs << iv
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
ivs
|
|
450
|
+
end
|
|
451
|
+
# :nocov:
|
|
452
|
+
else
|
|
453
|
+
def make_shape_friendly # :nodoc:
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
# :nocov:
|
|
379
457
|
end
|
|
380
458
|
|
|
381
459
|
def self.inherited(subclass)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rodauth
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.44.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeremy Evans
|
|
@@ -403,7 +403,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
403
403
|
- !ruby/object:Gem::Version
|
|
404
404
|
version: '0'
|
|
405
405
|
requirements: []
|
|
406
|
-
rubygems_version: 4.0.
|
|
406
|
+
rubygems_version: 4.0.10
|
|
407
407
|
specification_version: 4
|
|
408
408
|
summary: Authentication and Account Management Framework for Rack Applications
|
|
409
409
|
test_files: []
|