rodauth 1.23.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +184 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +221 -79
- data/doc/account_expiration.rdoc +12 -26
- data/doc/active_sessions.rdoc +49 -0
- data/doc/audit_logging.rdoc +44 -0
- data/doc/base.rdoc +76 -128
- data/doc/change_login.rdoc +7 -14
- data/doc/change_password.rdoc +9 -13
- data/doc/change_password_notify.rdoc +2 -2
- data/doc/close_account.rdoc +9 -16
- data/doc/confirm_password.rdoc +12 -5
- data/doc/create_account.rdoc +11 -22
- data/doc/disallow_password_reuse.rdoc +6 -13
- data/doc/email_auth.rdoc +15 -14
- data/doc/email_base.rdoc +5 -15
- data/doc/guides/admin_activation.rdoc +46 -0
- data/doc/guides/already_authenticated.rdoc +10 -0
- data/doc/guides/alternative_login.rdoc +46 -0
- data/doc/guides/create_account_programmatically.rdoc +38 -0
- data/doc/guides/delay_password.rdoc +25 -0
- data/doc/guides/email_only.rdoc +16 -0
- data/doc/guides/i18n.rdoc +26 -0
- data/doc/{internals.rdoc → guides/internals.rdoc} +0 -0
- data/doc/guides/links.rdoc +12 -0
- data/doc/guides/login_return.rdoc +37 -0
- data/doc/guides/password_column.rdoc +25 -0
- data/doc/guides/password_confirmation.rdoc +37 -0
- data/doc/guides/password_requirements.rdoc +30 -0
- data/doc/guides/paths.rdoc +36 -0
- data/doc/guides/query_params.rdoc +9 -0
- data/doc/guides/redirects.rdoc +17 -0
- data/doc/guides/registration_field.rdoc +68 -0
- data/doc/guides/require_mfa.rdoc +30 -0
- data/doc/guides/reset_password_autologin.rdoc +21 -0
- data/doc/guides/status_column.rdoc +28 -0
- data/doc/guides/totp_or_recovery.rdoc +16 -0
- data/doc/http_basic_auth.rdoc +10 -1
- data/doc/jwt.rdoc +22 -22
- data/doc/jwt_cors.rdoc +2 -3
- data/doc/jwt_refresh.rdoc +23 -8
- data/doc/lockout.rdoc +17 -15
- data/doc/login.rdoc +17 -2
- data/doc/login_password_requirements_base.rdoc +18 -37
- data/doc/logout.rdoc +2 -2
- data/doc/otp.rdoc +25 -19
- data/doc/password_complexity.rdoc +10 -26
- data/doc/password_expiration.rdoc +11 -25
- data/doc/password_grace_period.rdoc +16 -2
- data/doc/password_pepper.rdoc +44 -0
- data/doc/recovery_codes.rdoc +18 -12
- data/doc/release_notes/2.0.0.txt +361 -0
- data/doc/release_notes/2.1.0.txt +31 -0
- data/doc/release_notes/2.2.0.txt +39 -0
- data/doc/release_notes/2.3.0.txt +37 -0
- data/doc/release_notes/2.4.0.txt +22 -0
- data/doc/remember.rdoc +40 -64
- data/doc/reset_password.rdoc +12 -9
- data/doc/session_expiration.rdoc +1 -0
- data/doc/single_session.rdoc +16 -25
- data/doc/sms_codes.rdoc +24 -14
- data/doc/two_factor_base.rdoc +60 -22
- data/doc/verify_account.rdoc +14 -12
- data/doc/verify_account_grace_period.rdoc +6 -2
- data/doc/verify_login_change.rdoc +9 -8
- data/doc/webauthn.rdoc +115 -0
- data/doc/webauthn_login.rdoc +15 -0
- data/doc/webauthn_verify_account.rdoc +9 -0
- data/javascript/webauthn_auth.js +45 -0
- data/javascript/webauthn_setup.js +35 -0
- data/lib/roda/plugins/rodauth.rb +1 -1
- data/lib/rodauth.rb +33 -28
- data/lib/rodauth/features/account_expiration.rb +5 -5
- data/lib/rodauth/features/active_sessions.rb +158 -0
- data/lib/rodauth/features/audit_logging.rb +98 -0
- data/lib/rodauth/features/base.rb +152 -49
- data/lib/rodauth/features/change_password_notify.rb +1 -1
- data/lib/rodauth/features/close_account.rb +8 -6
- data/lib/rodauth/features/confirm_password.rb +40 -2
- data/lib/rodauth/features/create_account.rb +8 -13
- data/lib/rodauth/features/disallow_common_passwords.rb +1 -1
- data/lib/rodauth/features/disallow_password_reuse.rb +5 -3
- data/lib/rodauth/features/email_auth.rb +30 -28
- data/lib/rodauth/features/email_base.rb +3 -3
- data/lib/rodauth/features/http_basic_auth.rb +55 -35
- data/lib/rodauth/features/jwt.rb +63 -16
- data/lib/rodauth/features/jwt_cors.rb +15 -15
- data/lib/rodauth/features/jwt_refresh.rb +42 -13
- data/lib/rodauth/features/lockout.rb +11 -13
- data/lib/rodauth/features/login.rb +58 -13
- data/lib/rodauth/features/login_password_requirements_base.rb +13 -8
- data/lib/rodauth/features/otp.rb +76 -82
- data/lib/rodauth/features/password_complexity.rb +8 -13
- data/lib/rodauth/features/password_expiration.rb +1 -1
- data/lib/rodauth/features/password_grace_period.rb +17 -10
- data/lib/rodauth/features/password_pepper.rb +45 -0
- data/lib/rodauth/features/recovery_codes.rb +47 -51
- data/lib/rodauth/features/remember.rb +13 -27
- data/lib/rodauth/features/reset_password.rb +25 -25
- data/lib/rodauth/features/session_expiration.rb +7 -10
- data/lib/rodauth/features/single_session.rb +8 -6
- data/lib/rodauth/features/sms_codes.rb +58 -68
- data/lib/rodauth/features/two_factor_base.rb +134 -30
- data/lib/rodauth/features/verify_account.rb +28 -20
- data/lib/rodauth/features/verify_account_grace_period.rb +18 -9
- data/lib/rodauth/features/verify_login_change.rb +11 -10
- data/lib/rodauth/features/webauthn.rb +505 -0
- data/lib/rodauth/features/webauthn_login.rb +70 -0
- data/lib/rodauth/features/webauthn_verify_account.rb +46 -0
- data/lib/rodauth/migrations.rb +16 -5
- data/lib/rodauth/version.rb +2 -2
- data/templates/button.str +1 -3
- data/templates/change-login.str +1 -2
- data/templates/change-password.str +3 -5
- data/templates/close-account.str +2 -2
- data/templates/confirm-password.str +1 -1
- data/templates/create-account.str +1 -1
- data/templates/email-auth-request-form.str +1 -2
- data/templates/email-auth.str +1 -1
- data/templates/global-logout-field.str +6 -0
- data/templates/login-confirm-field.str +2 -4
- data/templates/login-display.str +3 -2
- data/templates/login-field.str +2 -4
- data/templates/login-form-footer.str +6 -0
- data/templates/login-form.str +7 -0
- data/templates/login.str +1 -9
- data/templates/logout.str +1 -1
- data/templates/multi-phase-login.str +3 -0
- data/templates/otp-auth-code-field.str +5 -3
- data/templates/otp-auth.str +1 -1
- data/templates/otp-disable.str +1 -1
- data/templates/otp-setup.str +3 -3
- data/templates/password-confirm-field.str +2 -4
- data/templates/password-field.str +2 -4
- data/templates/recovery-auth.str +3 -6
- data/templates/recovery-codes.str +1 -1
- data/templates/remember.str +15 -20
- data/templates/reset-password-request.str +2 -2
- data/templates/reset-password.str +1 -2
- data/templates/sms-auth.str +1 -1
- data/templates/sms-code-field.str +5 -3
- data/templates/sms-confirm.str +1 -2
- data/templates/sms-disable.str +1 -2
- data/templates/sms-request.str +1 -1
- data/templates/sms-setup.str +6 -4
- data/templates/two-factor-auth.str +5 -0
- data/templates/two-factor-disable.str +6 -0
- data/templates/two-factor-manage.str +16 -0
- data/templates/unlock-account-request.str +2 -2
- data/templates/unlock-account.str +1 -1
- data/templates/verify-account-resend.str +1 -1
- data/templates/verify-account.str +1 -2
- data/templates/verify-login-change.str +1 -1
- data/templates/webauthn-auth.str +11 -0
- data/templates/webauthn-remove.str +14 -0
- data/templates/webauthn-setup.str +12 -0
- metadata +96 -13
- data/doc/verify_change_login.rdoc +0 -11
- data/lib/rodauth/features/verify_change_login.rb +0 -20
@@ -2,18 +2,20 @@
|
|
2
2
|
|
3
3
|
module Rodauth
|
4
4
|
Feature.define(:login_password_requirements_base, :LoginPasswordRequirementsBase) do
|
5
|
-
|
5
|
+
translatable_method :already_an_account_with_this_login_message, 'already an account with this login'
|
6
6
|
auth_value_method :login_confirm_param, 'login-confirm'
|
7
|
+
auth_value_method :login_email_regexp, /\A[^,;@ \r\n]+@[^,@; \r\n]+\.[^,@; \r\n]+\z/
|
7
8
|
auth_value_method :login_minimum_length, 3
|
8
9
|
auth_value_method :login_maximum_length, 255
|
9
|
-
|
10
|
+
translatable_method :login_not_valid_email_message, 'not a valid email address'
|
11
|
+
translatable_method :logins_do_not_match_message, 'logins do not match'
|
10
12
|
auth_value_method :password_confirm_param, 'password-confirm'
|
11
13
|
auth_value_method :password_minimum_length, 6
|
12
|
-
|
14
|
+
translatable_method :passwords_do_not_match_message, 'passwords do not match'
|
13
15
|
auth_value_method :require_email_address_logins?, true
|
14
16
|
auth_value_method :require_login_confirmation?, true
|
15
17
|
auth_value_method :require_password_confirmation?, true
|
16
|
-
|
18
|
+
translatable_method :same_as_existing_password_message, "invalid password, same as current password"
|
17
19
|
|
18
20
|
auth_value_methods(
|
19
21
|
:login_confirm_label,
|
@@ -28,6 +30,7 @@ module Rodauth
|
|
28
30
|
|
29
31
|
auth_methods(
|
30
32
|
:login_meets_requirements?,
|
33
|
+
:login_valid_email?,
|
31
34
|
:password_hash,
|
32
35
|
:password_meets_requirements?,
|
33
36
|
:set_password
|
@@ -104,13 +107,15 @@ module Rodauth
|
|
104
107
|
|
105
108
|
def login_meets_email_requirements?(login)
|
106
109
|
return true unless require_email_address_logins?
|
107
|
-
if login
|
108
|
-
|
109
|
-
end
|
110
|
-
@login_requirement_message = 'not a valid email address'
|
110
|
+
return true if login_valid_email?(login)
|
111
|
+
@login_requirement_message = login_not_valid_email_message
|
111
112
|
return false
|
112
113
|
end
|
113
114
|
|
115
|
+
def login_valid_email?(login)
|
116
|
+
login =~ login_email_regexp
|
117
|
+
end
|
118
|
+
|
114
119
|
def password_meets_length_requirements?(password)
|
115
120
|
return true if password_minimum_length <= password.length
|
116
121
|
@password_requirement_message = password_too_short_message
|
data/lib/rodauth/features/otp.rb
CHANGED
@@ -19,62 +19,59 @@ module Rodauth
|
|
19
19
|
before 'otp_setup'
|
20
20
|
before 'otp_disable'
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
before_otp_auth_route(&block)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
button 'Authenticate via 2nd Factor', 'otp_auth'
|
30
|
-
button 'Disable Two Factor Authentication', 'otp_disable'
|
31
|
-
button 'Setup Two Factor Authentication', 'otp_setup'
|
22
|
+
button 'Authenticate Using TOTP', 'otp_auth'
|
23
|
+
button 'Disable TOTP Authentication', 'otp_disable'
|
24
|
+
button 'Setup TOTP Authentication', 'otp_setup'
|
32
25
|
|
33
|
-
error_flash "Error disabling
|
34
|
-
error_flash "Error logging in via
|
35
|
-
error_flash "Error setting up
|
36
|
-
error_flash "You have already setup
|
26
|
+
error_flash "Error disabling TOTP authentication", 'otp_disable'
|
27
|
+
error_flash "Error logging in via TOTP authentication", 'otp_auth'
|
28
|
+
error_flash "Error setting up TOTP authentication", 'otp_setup'
|
29
|
+
error_flash "You have already setup TOTP authentication", 'otp_already_setup'
|
30
|
+
error_flash "TOTP authentication code use locked out due to numerous failures", 'otp_lockout'
|
37
31
|
|
38
|
-
notice_flash "
|
39
|
-
notice_flash "
|
32
|
+
notice_flash "TOTP authentication has been disabled", 'otp_disable'
|
33
|
+
notice_flash "TOTP authentication is now setup", 'otp_setup'
|
40
34
|
|
41
35
|
redirect :otp_disable
|
42
36
|
redirect :otp_already_setup
|
43
37
|
redirect :otp_setup
|
38
|
+
redirect(:otp_lockout){two_factor_auth_required_redirect}
|
44
39
|
|
45
40
|
loaded_templates %w'otp-disable otp-auth otp-setup otp-auth-code-field password-field'
|
46
|
-
view 'otp-disable', 'Disable
|
41
|
+
view 'otp-disable', 'Disable TOTP Authentication', 'otp_disable'
|
47
42
|
view 'otp-auth', 'Enter Authentication Code', 'otp_auth'
|
48
|
-
view 'otp-setup', 'Setup
|
43
|
+
view 'otp-setup', 'Setup TOTP Authentication', 'otp_setup'
|
44
|
+
|
45
|
+
translatable_method :otp_auth_link_text, "Authenticate Using TOTP"
|
46
|
+
translatable_method :otp_setup_link_text, "Setup TOTP Authentication"
|
47
|
+
translatable_method :otp_disable_link_text, "Disable TOTP Authentication"
|
49
48
|
|
50
49
|
auth_value_method :otp_auth_failures_limit, 5
|
51
|
-
|
50
|
+
translatable_method :otp_auth_label, 'Authentication Code'
|
52
51
|
auth_value_method :otp_auth_param, 'otp'
|
53
52
|
auth_value_method :otp_class, ROTP::TOTP
|
54
53
|
auth_value_method :otp_digits, nil
|
55
|
-
auth_value_method :otp_drift,
|
54
|
+
auth_value_method :otp_drift, 30
|
56
55
|
auth_value_method :otp_interval, nil
|
57
|
-
|
58
|
-
|
56
|
+
translatable_method :otp_invalid_auth_code_message, "Invalid authentication code"
|
57
|
+
translatable_method :otp_invalid_secret_message, "invalid secret"
|
59
58
|
auth_value_method :otp_keys_column, :key
|
60
59
|
auth_value_method :otp_keys_id_column, :id
|
61
60
|
auth_value_method :otp_keys_failures_column, :num_failures
|
62
61
|
auth_value_method :otp_keys_table, :account_otp_keys
|
63
62
|
auth_value_method :otp_keys_last_use_column, :last_use
|
64
|
-
|
65
|
-
|
63
|
+
translatable_method :otp_provisioning_uri_label, 'Provisioning URL'
|
64
|
+
translatable_method :otp_secret_label, 'Secret'
|
66
65
|
auth_value_method :otp_setup_param, 'otp_secret'
|
67
66
|
auth_value_method :otp_setup_raw_param, 'otp_raw_secret'
|
67
|
+
translatable_method :otp_auth_form_footer, ''
|
68
68
|
|
69
69
|
auth_cached_method :otp_key
|
70
70
|
auth_cached_method :otp
|
71
71
|
private :otp
|
72
72
|
|
73
73
|
auth_value_methods(
|
74
|
-
:otp_auth_form_footer,
|
75
74
|
:otp_issuer,
|
76
|
-
:otp_lockout_error_flash,
|
77
|
-
:otp_lockout_redirect,
|
78
75
|
:otp_keys_use_hmac?
|
79
76
|
)
|
80
77
|
|
@@ -82,6 +79,7 @@ module Rodauth
|
|
82
79
|
:otp,
|
83
80
|
:otp_exists?,
|
84
81
|
:otp_key,
|
82
|
+
:otp_last_use,
|
85
83
|
:otp_locked_out?,
|
86
84
|
:otp_new_secret,
|
87
85
|
:otp_provisioning_name,
|
@@ -103,18 +101,13 @@ module Rodauth
|
|
103
101
|
route(:otp_auth) do |r|
|
104
102
|
require_login
|
105
103
|
require_account_session
|
106
|
-
require_two_factor_not_authenticated
|
104
|
+
require_two_factor_not_authenticated('totp')
|
107
105
|
require_otp_setup
|
108
106
|
|
109
107
|
if otp_locked_out?
|
110
108
|
set_response_error_status(lockout_error_status)
|
111
109
|
set_redirect_error_flash otp_lockout_error_flash
|
112
|
-
|
113
|
-
redirect redir
|
114
|
-
else
|
115
|
-
clear_session
|
116
|
-
redirect require_login_redirect
|
117
|
-
end
|
110
|
+
redirect otp_lockout_redirect
|
118
111
|
end
|
119
112
|
|
120
113
|
before_otp_auth_route
|
@@ -126,7 +119,7 @@ module Rodauth
|
|
126
119
|
r.post do
|
127
120
|
if otp_valid_code?(param(otp_auth_param)) && otp_update_last_use
|
128
121
|
before_otp_authentication
|
129
|
-
two_factor_authenticate(
|
122
|
+
two_factor_authenticate('totp')
|
130
123
|
end
|
131
124
|
|
132
125
|
otp_record_authentication_failure
|
@@ -178,7 +171,9 @@ module Rodauth
|
|
178
171
|
transaction do
|
179
172
|
before_otp_setup
|
180
173
|
otp_add_key
|
181
|
-
|
174
|
+
unless two_factor_authenticated?
|
175
|
+
two_factor_update_session('totp')
|
176
|
+
end
|
182
177
|
after_otp_setup
|
183
178
|
end
|
184
179
|
set_notice_flash otp_setup_notice_flash
|
@@ -204,7 +199,9 @@ module Rodauth
|
|
204
199
|
transaction do
|
205
200
|
before_otp_disable
|
206
201
|
otp_remove
|
207
|
-
|
202
|
+
if two_factor_login_type_match?('totp')
|
203
|
+
two_factor_remove_session('totp')
|
204
|
+
end
|
208
205
|
after_otp_disable
|
209
206
|
end
|
210
207
|
set_notice_flash otp_disable_notice_flash
|
@@ -218,20 +215,6 @@ module Rodauth
|
|
218
215
|
end
|
219
216
|
end
|
220
217
|
|
221
|
-
def two_factor_authentication_setup?
|
222
|
-
return true if super
|
223
|
-
return false if @otp_tmp_key
|
224
|
-
otp_exists?
|
225
|
-
end
|
226
|
-
|
227
|
-
def two_factor_need_setup_redirect
|
228
|
-
otp_setup_path
|
229
|
-
end
|
230
|
-
|
231
|
-
def two_factor_auth_required_redirect
|
232
|
-
otp_auth_path
|
233
|
-
end
|
234
|
-
|
235
218
|
def two_factor_remove
|
236
219
|
super
|
237
220
|
otp_remove
|
@@ -242,19 +225,6 @@ module Rodauth
|
|
242
225
|
otp_remove_auth_failures
|
243
226
|
end
|
244
227
|
|
245
|
-
def otp_auth_form_footer
|
246
|
-
super if defined?(super)
|
247
|
-
end
|
248
|
-
|
249
|
-
def otp_lockout_redirect
|
250
|
-
return super if defined?(super)
|
251
|
-
nil
|
252
|
-
end
|
253
|
-
|
254
|
-
def otp_lockout_error_flash
|
255
|
-
"Authentication code use locked out due to numerous failures.#{super if defined?(super)}"
|
256
|
-
end
|
257
|
-
|
258
228
|
def require_otp_setup
|
259
229
|
unless otp_exists?
|
260
230
|
set_redirect_error_status(two_factor_not_setup_error_status)
|
@@ -272,11 +242,11 @@ module Rodauth
|
|
272
242
|
ot_pass = ot_pass.gsub(/\s+/, '')
|
273
243
|
if drift = otp_drift
|
274
244
|
if otp.respond_to?(:verify_with_drift)
|
245
|
+
# :nocov:
|
275
246
|
otp.verify_with_drift(ot_pass, drift)
|
276
|
-
else
|
277
247
|
# :nocov:
|
248
|
+
else
|
278
249
|
otp.verify(ot_pass, :drift_behind=>drift, :drift_ahead=>drift)
|
279
|
-
# :nocov:
|
280
250
|
end
|
281
251
|
else
|
282
252
|
otp.verify(ot_pass)
|
@@ -285,7 +255,7 @@ module Rodauth
|
|
285
255
|
|
286
256
|
def otp_remove
|
287
257
|
otp_key_ds.delete
|
288
|
-
|
258
|
+
@otp_key = nil
|
289
259
|
end
|
290
260
|
|
291
261
|
def otp_add_key
|
@@ -299,6 +269,10 @@ module Rodauth
|
|
299
269
|
update(otp_keys_last_use_column=>Sequel::CURRENT_TIMESTAMP) == 1
|
300
270
|
end
|
301
271
|
|
272
|
+
def otp_last_use
|
273
|
+
convert_timestamp(otp_key_ds.get(otp_keys_last_use_column))
|
274
|
+
end
|
275
|
+
|
302
276
|
def otp_record_authentication_failure
|
303
277
|
otp_key_ds.update(otp_keys_failures_column=>Sequel.identifier(otp_keys_failures_column) + 1)
|
304
278
|
end
|
@@ -316,7 +290,7 @@ module Rodauth
|
|
316
290
|
end
|
317
291
|
|
318
292
|
def otp_issuer
|
319
|
-
|
293
|
+
domain
|
320
294
|
end
|
321
295
|
|
322
296
|
def otp_provisioning_name
|
@@ -339,8 +313,37 @@ module Rodauth
|
|
339
313
|
!!hmac_secret
|
340
314
|
end
|
341
315
|
|
316
|
+
def possible_authentication_methods
|
317
|
+
methods = super
|
318
|
+
methods << 'totp' if otp_exists? && !@otp_tmp_key
|
319
|
+
methods
|
320
|
+
end
|
321
|
+
|
342
322
|
private
|
343
323
|
|
324
|
+
def _two_factor_auth_links
|
325
|
+
links = super
|
326
|
+
links << [20, otp_auth_path, otp_auth_link_text] if otp_exists? && !otp_locked_out?
|
327
|
+
links
|
328
|
+
end
|
329
|
+
|
330
|
+
def _two_factor_setup_links
|
331
|
+
links = super
|
332
|
+
links << [20, otp_setup_path, otp_setup_link_text] unless otp_exists?
|
333
|
+
links
|
334
|
+
end
|
335
|
+
|
336
|
+
def _two_factor_remove_links
|
337
|
+
links = super
|
338
|
+
links << [20, otp_disable_path, otp_disable_link_text] if otp_exists?
|
339
|
+
links
|
340
|
+
end
|
341
|
+
|
342
|
+
def _two_factor_remove_all_from_session
|
343
|
+
two_factor_remove_session('totp')
|
344
|
+
super
|
345
|
+
end
|
346
|
+
|
344
347
|
def clear_cached_otp
|
345
348
|
remove_instance_variable(:@otp) if defined?(@otp)
|
346
349
|
end
|
@@ -364,29 +367,20 @@ module Rodauth
|
|
364
367
|
end
|
365
368
|
|
366
369
|
if ROTP::Base32.respond_to?(:random_base32)
|
367
|
-
# :nocov:
|
368
370
|
def otp_new_secret
|
369
371
|
ROTP::Base32.random_base32.downcase
|
370
372
|
end
|
371
|
-
# :nocov:
|
372
373
|
else
|
374
|
+
# :nocov:
|
373
375
|
def otp_new_secret
|
374
376
|
ROTP::Base32.random.downcase
|
375
377
|
end
|
378
|
+
# :nocov:
|
376
379
|
end
|
377
380
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
chars = 'abcdefghijklmnopqrstuvwxyz234567'
|
382
|
-
length.times.map{|i|chars[data[i] % 32].chr}.join
|
383
|
-
end
|
384
|
-
# :nocov:
|
385
|
-
else
|
386
|
-
def base32_encode(data, length)
|
387
|
-
chars = 'abcdefghijklmnopqrstuvwxyz234567'
|
388
|
-
length.times.map{|i|chars[data[i].ord % 32]}.join
|
389
|
-
end
|
381
|
+
def base32_encode(data, length)
|
382
|
+
chars = 'abcdefghijklmnopqrstuvwxyz234567'
|
383
|
+
length.times.map{|i|chars[data[i].ord % 32]}.join
|
390
384
|
end
|
391
385
|
|
392
386
|
def _otp_tmp_key(secret)
|
@@ -11,13 +11,10 @@ module Rodauth
|
|
11
11
|
auth_value_method :password_max_length_for_groups_check, 11
|
12
12
|
auth_value_method :password_max_repeating_characters, 3
|
13
13
|
auth_value_method :password_invalid_pattern, Regexp.union([/qwerty/i, /azerty/i, /asdf/i, /zxcv/i] + (1..8).map{|i| /#{i}#{i+1}#{(i+2)%10}/})
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
auth_value_methods(
|
19
|
-
:password_too_many_repeating_characters_message
|
20
|
-
)
|
14
|
+
translatable_method :password_not_enough_character_groups_message, "does not include uppercase letters, lowercase letters, and numbers"
|
15
|
+
translatable_method :password_invalid_pattern_message, "includes common character sequence"
|
16
|
+
translatable_method :password_in_dictionary_message, "is a word in a dictionary"
|
17
|
+
translatable_method :password_too_many_repeating_characters_message, "contains too many of the same character in a row"
|
21
18
|
|
22
19
|
def password_meets_requirements?(password)
|
23
20
|
super && \
|
@@ -29,14 +26,16 @@ module Rodauth
|
|
29
26
|
|
30
27
|
def post_configure
|
31
28
|
super
|
32
|
-
return if
|
29
|
+
return if method(:password_dictionary).owner != Rodauth::PasswordComplexity
|
33
30
|
|
34
31
|
case password_dictionary_file
|
35
32
|
when false
|
36
|
-
|
33
|
+
# nothing
|
37
34
|
when nil
|
38
35
|
default_dictionary_file = '/usr/share/dict/words'
|
36
|
+
# :nocov:
|
39
37
|
if File.file?(default_dictionary_file)
|
38
|
+
# :nocov:
|
40
39
|
words = File.read(default_dictionary_file)
|
41
40
|
end
|
42
41
|
else
|
@@ -73,10 +72,6 @@ module Rodauth
|
|
73
72
|
false
|
74
73
|
end
|
75
74
|
|
76
|
-
def password_too_many_repeating_characters_message
|
77
|
-
"contains #{password_max_repeating_characters} or more of the same character in a row"
|
78
|
-
end
|
79
|
-
|
80
75
|
def password_not_in_dictionary?(password)
|
81
76
|
return true unless dict = password_dictionary
|
82
77
|
return true unless password =~ /\A(?:\d*)([A-Za-z!@$+|][A-Za-z!@$+|0134578]+[A-Za-z!@$+|])(?:\d*)\z/
|
@@ -5,6 +5,8 @@ module Rodauth
|
|
5
5
|
auth_value_method :password_grace_period, 300
|
6
6
|
session_key :last_password_entry_session_key, :last_password_entry
|
7
7
|
|
8
|
+
auth_methods :password_recently_entered?
|
9
|
+
|
8
10
|
def modifications_require_password?
|
9
11
|
return false unless super
|
10
12
|
!password_recently_entered?
|
@@ -17,6 +19,16 @@ module Rodauth
|
|
17
19
|
v
|
18
20
|
end
|
19
21
|
|
22
|
+
def password_recently_entered?
|
23
|
+
return false unless last_password_entry = session[last_password_entry_session_key]
|
24
|
+
last_password_entry + password_grace_period > Time.now.to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_session
|
28
|
+
super
|
29
|
+
set_session_value(last_password_entry_session_key, @last_password_entry) if defined?(@last_password_entry)
|
30
|
+
end
|
31
|
+
|
20
32
|
private
|
21
33
|
|
22
34
|
def after_create_account
|
@@ -29,18 +41,13 @@ module Rodauth
|
|
29
41
|
@last_password_entry = Time.now.to_i
|
30
42
|
end
|
31
43
|
|
32
|
-
def
|
33
|
-
|
34
|
-
session[last_password_entry_session_key] = @last_password_entry if defined?(@last_password_entry)
|
35
|
-
end
|
36
|
-
|
37
|
-
def password_recently_entered?
|
38
|
-
return false unless last_password_entry = session[last_password_entry_session_key]
|
39
|
-
last_password_entry + password_grace_period > Time.now.to_i
|
44
|
+
def set_last_password_entry
|
45
|
+
set_session_value(last_password_entry_session_key, Time.now.to_i)
|
40
46
|
end
|
41
47
|
|
42
|
-
def
|
43
|
-
|
48
|
+
def require_password_authentication?
|
49
|
+
return true if defined?(super) && super
|
50
|
+
!password_recently_entered?
|
44
51
|
end
|
45
52
|
end
|
46
53
|
end
|