rodauth 1.21.0 → 2.2.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 +182 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +211 -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 +75 -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 +6 -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 +22 -0
- data/doc/jwt_refresh.rdoc +18 -8
- data/doc/lockout.rdoc +17 -15
- data/doc/login.rdoc +10 -2
- data/doc/login_password_requirements_base.rdoc +15 -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/recovery_codes.rdoc +18 -12
- data/doc/release_notes/1.22.0.txt +11 -0
- data/doc/release_notes/1.23.0.txt +32 -0
- 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/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 +36 -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 +144 -43
- data/lib/rodauth/features/change_password_notify.rb +2 -2
- 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 +1 -1
- data/lib/rodauth/features/email_auth.rb +31 -30
- data/lib/rodauth/features/email_base.rb +9 -4
- 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 +53 -0
- data/lib/rodauth/features/jwt_refresh.rb +32 -9
- data/lib/rodauth/features/lockout.rb +12 -14
- data/lib/rodauth/features/login.rb +54 -10
- data/lib/rodauth/features/login_password_requirements_base.rb +4 -4
- data/lib/rodauth/features/otp.rb +77 -80
- data/lib/rodauth/features/password_complexity.rb +8 -13
- data/lib/rodauth/features/password_expiration.rb +2 -2
- data/lib/rodauth/features/password_grace_period.rb +17 -10
- data/lib/rodauth/features/recovery_codes.rb +49 -53
- data/lib/rodauth/features/remember.rb +11 -27
- data/lib/rodauth/features/reset_password.rb +26 -26
- data/lib/rodauth/features/session_expiration.rb +6 -4
- data/lib/rodauth/features/single_session.rb +8 -6
- data/lib/rodauth/features/sms_codes.rb +62 -72
- data/lib/rodauth/features/two_factor_base.rb +134 -30
- data/lib/rodauth/features/verify_account.rb +29 -21
- data/lib/rodauth/features/verify_account_grace_period.rb +18 -9
- data/lib/rodauth/features/verify_login_change.rb +12 -11
- 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/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-email.str +1 -1
- data/templates/email-auth-request-form.str +2 -3
- 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-email.str +1 -1
- data/templates/reset-password-request.str +3 -3
- 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-email.str +1 -1
- data/templates/unlock-account-request.str +4 -4
- data/templates/unlock-account.str +1 -1
- data/templates/verify-account-email.str +1 -1
- data/templates/verify-account-resend.str +3 -3
- data/templates/verify-account.str +1 -2
- data/templates/verify-login-change-email.str +2 -1
- 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 +110 -52
- data/Rakefile +0 -179
- data/doc/verify_change_login.rdoc +0 -11
- data/lib/rodauth/features/verify_change_login.rb +0 -20
- data/spec/account_expiration_spec.rb +0 -225
- data/spec/all.rb +0 -1
- data/spec/change_login_spec.rb +0 -156
- data/spec/change_password_notify_spec.rb +0 -33
- data/spec/change_password_spec.rb +0 -202
- data/spec/close_account_spec.rb +0 -162
- data/spec/confirm_password_spec.rb +0 -70
- data/spec/create_account_spec.rb +0 -127
- data/spec/disallow_common_passwords_spec.rb +0 -93
- data/spec/disallow_password_reuse_spec.rb +0 -179
- data/spec/email_auth_spec.rb +0 -285
- data/spec/http_basic_auth_spec.rb +0 -143
- data/spec/jwt_refresh_spec.rb +0 -256
- data/spec/jwt_spec.rb +0 -235
- data/spec/lockout_spec.rb +0 -250
- data/spec/login_spec.rb +0 -328
- data/spec/migrate/001_tables.rb +0 -184
- data/spec/migrate/002_account_password_hash_column.rb +0 -11
- data/spec/migrate_password/001_tables.rb +0 -73
- data/spec/migrate_travis/001_tables.rb +0 -141
- data/spec/password_complexity_spec.rb +0 -109
- data/spec/password_expiration_spec.rb +0 -244
- data/spec/password_grace_period_spec.rb +0 -93
- data/spec/remember_spec.rb +0 -451
- data/spec/reset_password_spec.rb +0 -229
- data/spec/rodauth_spec.rb +0 -343
- data/spec/session_expiration_spec.rb +0 -58
- data/spec/single_session_spec.rb +0 -127
- data/spec/spec_helper.rb +0 -327
- data/spec/two_factor_spec.rb +0 -1462
- data/spec/update_password_hash_spec.rb +0 -40
- data/spec/verify_account_grace_period_spec.rb +0 -171
- data/spec/verify_account_spec.rb +0 -240
- data/spec/verify_change_login_spec.rb +0 -46
- data/spec/verify_login_change_spec.rb +0 -232
- data/spec/views/layout-other.str +0 -11
- data/spec/views/layout.str +0 -11
- data/spec/views/login.str +0 -21
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module Rodauth
|
|
4
4
|
Feature.define(:remember, :Remember) do
|
|
5
|
-
depends :confirm_password
|
|
6
|
-
|
|
7
5
|
notice_flash "Your remember setting has been updated"
|
|
8
6
|
error_flash "There was an error updating your remember setting"
|
|
9
7
|
loaded_templates %w'remember'
|
|
@@ -17,11 +15,10 @@ module Rodauth
|
|
|
17
15
|
redirect
|
|
18
16
|
|
|
19
17
|
auth_value_method :raw_remember_token_deadline, nil
|
|
20
|
-
auth_value_method :remember_cookie_options, {}
|
|
18
|
+
auth_value_method :remember_cookie_options, {}.freeze
|
|
21
19
|
auth_value_method :extend_remember_deadline?, false
|
|
22
|
-
auth_value_method :remember_period, {:days=>14}
|
|
23
|
-
|
|
24
|
-
auth_value_method :remember_deadline_interval, {:days=>14}
|
|
20
|
+
auth_value_method :remember_period, {:days=>14}.freeze
|
|
21
|
+
auth_value_method :remember_deadline_interval, {:days=>14}.freeze
|
|
25
22
|
auth_value_method :remember_id_column, :id
|
|
26
23
|
auth_value_method :remember_key_column, :key
|
|
27
24
|
auth_value_method :remember_deadline_column, :deadline
|
|
@@ -31,13 +28,12 @@ module Rodauth
|
|
|
31
28
|
auth_value_method :remember_remember_param_value, 'remember'
|
|
32
29
|
auth_value_method :remember_forget_param_value, 'forget'
|
|
33
30
|
auth_value_method :remember_disable_param_value, 'disable'
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
translatable_method :remember_remember_label, 'Remember Me'
|
|
32
|
+
translatable_method :remember_forget_label, 'Forget Me'
|
|
33
|
+
translatable_method :remember_disable_label, 'Disable Remember Me'
|
|
37
34
|
|
|
38
35
|
auth_methods(
|
|
39
36
|
:add_remember_key,
|
|
40
|
-
:clear_remembered_session_key,
|
|
41
37
|
:disable_remember_login,
|
|
42
38
|
:forget_login,
|
|
43
39
|
:generate_remember_key_value,
|
|
@@ -109,9 +105,9 @@ module Rodauth
|
|
|
109
105
|
return
|
|
110
106
|
end
|
|
111
107
|
|
|
112
|
-
|
|
108
|
+
set_session_value(session_key, id)
|
|
113
109
|
account = account_from_session
|
|
114
|
-
|
|
110
|
+
remove_session_value(session_key)
|
|
115
111
|
|
|
116
112
|
unless account
|
|
117
113
|
remove_remember_key(id)
|
|
@@ -120,9 +116,8 @@ module Rodauth
|
|
|
120
116
|
end
|
|
121
117
|
|
|
122
118
|
before_load_memory
|
|
123
|
-
|
|
119
|
+
login_session('remember')
|
|
124
120
|
|
|
125
|
-
set_session_value(remembered_session_key, true)
|
|
126
121
|
if extend_remember_deadline?
|
|
127
122
|
active_remember_key_ds(id).update(remember_deadline_column=>Sequel.date_add(Sequel::CURRENT_TIMESTAMP, remember_period))
|
|
128
123
|
remember_login
|
|
@@ -133,9 +128,7 @@ module Rodauth
|
|
|
133
128
|
def remember_login
|
|
134
129
|
get_remember_key
|
|
135
130
|
opts = Hash[remember_cookie_options]
|
|
136
|
-
|
|
137
|
-
key = compute_hmac(key) if hmac_secret
|
|
138
|
-
opts[:value] = "#{account_id}_#{key}"
|
|
131
|
+
opts[:value] = "#{account_id}_#{convert_token_key(remember_key_value)}"
|
|
139
132
|
opts[:expires] = convert_timestamp(active_remember_key_ds.get(remember_deadline_column))
|
|
140
133
|
::Rack::Utils.set_cookie_header!(response.headers, remember_cookie_key, opts)
|
|
141
134
|
end
|
|
@@ -174,12 +167,8 @@ module Rodauth
|
|
|
174
167
|
remember_key_ds(id).delete
|
|
175
168
|
end
|
|
176
169
|
|
|
177
|
-
def clear_remembered_session_key
|
|
178
|
-
session.delete(remembered_session_key)
|
|
179
|
-
end
|
|
180
|
-
|
|
181
170
|
def logged_in_via_remember_key?
|
|
182
|
-
|
|
171
|
+
authenticated_by.include?('remember')
|
|
183
172
|
end
|
|
184
173
|
|
|
185
174
|
private
|
|
@@ -194,11 +183,6 @@ module Rodauth
|
|
|
194
183
|
super if defined?(super)
|
|
195
184
|
end
|
|
196
185
|
|
|
197
|
-
def after_confirm_password
|
|
198
|
-
super
|
|
199
|
-
clear_remembered_session_key
|
|
200
|
-
end
|
|
201
|
-
|
|
202
186
|
attr_reader :remember_key_value
|
|
203
187
|
|
|
204
188
|
def generate_remember_key_value
|
|
@@ -4,8 +4,6 @@ module Rodauth
|
|
|
4
4
|
Feature.define(:reset_password, :ResetPassword) do
|
|
5
5
|
depends :login, :email_base, :login_password_requirements_base
|
|
6
6
|
|
|
7
|
-
def_deprecated_alias :no_matching_reset_password_key_error_flash, :no_matching_reset_password_key_message
|
|
8
|
-
|
|
9
7
|
notice_flash "Your password has been reset"
|
|
10
8
|
notice_flash "An email has been sent to you with a link to reset the password for your account", 'reset_password_email_sent'
|
|
11
9
|
error_flash "There was an error resetting your password"
|
|
@@ -28,20 +26,19 @@ module Rodauth
|
|
|
28
26
|
redirect(:reset_password_email_recently_sent){default_post_email_redirect}
|
|
29
27
|
|
|
30
28
|
auth_value_method :reset_password_deadline_column, :deadline
|
|
31
|
-
auth_value_method :reset_password_deadline_interval, {:days=>1}
|
|
32
|
-
|
|
29
|
+
auth_value_method :reset_password_deadline_interval, {:days=>1}.freeze
|
|
30
|
+
translatable_method :reset_password_email_subject, 'Reset Password'
|
|
33
31
|
auth_value_method :reset_password_key_param, 'key'
|
|
34
32
|
auth_value_method :reset_password_autologin?, false
|
|
35
33
|
auth_value_method :reset_password_table, :account_password_reset_keys
|
|
36
34
|
auth_value_method :reset_password_id_column, :id
|
|
37
35
|
auth_value_method :reset_password_key_column, :key
|
|
38
|
-
auth_value_method :reset_password_email_last_sent_column,
|
|
39
|
-
|
|
36
|
+
auth_value_method :reset_password_email_last_sent_column, :email_last_sent
|
|
37
|
+
translatable_method :reset_password_explanatory_text, "<p>If you have forgotten your password, you can request a password reset:</p>"
|
|
40
38
|
auth_value_method :reset_password_skip_resend_email_within, 300
|
|
39
|
+
translatable_method :reset_password_request_link_text, "Forgot Password?"
|
|
41
40
|
session_key :reset_password_session_key, :reset_password_key
|
|
42
41
|
|
|
43
|
-
auth_value_methods :reset_password_request_link
|
|
44
|
-
|
|
45
42
|
auth_methods(
|
|
46
43
|
:create_reset_password_key,
|
|
47
44
|
:create_reset_password_email,
|
|
@@ -69,7 +66,15 @@ module Rodauth
|
|
|
69
66
|
end
|
|
70
67
|
|
|
71
68
|
r.post do
|
|
72
|
-
|
|
69
|
+
catch_error do
|
|
70
|
+
unless account_from_login(param(login_param))
|
|
71
|
+
throw_error_status(no_matching_login_error_status, login_param, no_matching_login_message)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
unless open_account?
|
|
75
|
+
throw_error_status(unopen_account_error_status, login_param, unverified_account_message)
|
|
76
|
+
end
|
|
77
|
+
|
|
73
78
|
if reset_password_email_recently_sent?
|
|
74
79
|
set_redirect_error_flash reset_password_email_recently_sent_error_flash
|
|
75
80
|
redirect reset_password_email_recently_sent_redirect
|
|
@@ -84,12 +89,11 @@ module Rodauth
|
|
|
84
89
|
end
|
|
85
90
|
|
|
86
91
|
set_notice_flash reset_password_email_sent_notice_flash
|
|
87
|
-
|
|
88
|
-
set_redirect_error_status(no_matching_login_error_status)
|
|
89
|
-
set_redirect_error_flash reset_password_request_error_flash
|
|
92
|
+
redirect reset_password_email_sent_redirect
|
|
90
93
|
end
|
|
91
94
|
|
|
92
|
-
|
|
95
|
+
set_error_flash reset_password_request_error_flash
|
|
96
|
+
reset_password_request_view
|
|
93
97
|
end
|
|
94
98
|
end
|
|
95
99
|
|
|
@@ -99,7 +103,7 @@ module Rodauth
|
|
|
99
103
|
|
|
100
104
|
r.get do
|
|
101
105
|
if key = param_or_nil(reset_password_key_param)
|
|
102
|
-
|
|
106
|
+
set_session_value(reset_password_session_key, key)
|
|
103
107
|
redirect(r.path)
|
|
104
108
|
end
|
|
105
109
|
|
|
@@ -107,7 +111,7 @@ module Rodauth
|
|
|
107
111
|
if account_from_reset_password_key(key)
|
|
108
112
|
reset_password_view
|
|
109
113
|
else
|
|
110
|
-
|
|
114
|
+
remove_session_value(reset_password_session_key)
|
|
111
115
|
set_redirect_error_flash no_matching_reset_password_key_error_flash
|
|
112
116
|
redirect require_login_redirect
|
|
113
117
|
end
|
|
@@ -144,10 +148,10 @@ module Rodauth
|
|
|
144
148
|
end
|
|
145
149
|
|
|
146
150
|
if reset_password_autologin?
|
|
147
|
-
|
|
151
|
+
autologin_session('reset_password')
|
|
148
152
|
end
|
|
149
153
|
|
|
150
|
-
|
|
154
|
+
remove_session_value(reset_password_session_key)
|
|
151
155
|
set_notice_flash reset_password_notice_flash
|
|
152
156
|
redirect reset_password_redirect
|
|
153
157
|
end
|
|
@@ -179,7 +183,7 @@ module Rodauth
|
|
|
179
183
|
end
|
|
180
184
|
|
|
181
185
|
def send_reset_password_email
|
|
182
|
-
create_reset_password_email
|
|
186
|
+
send_email(create_reset_password_email)
|
|
183
187
|
end
|
|
184
188
|
|
|
185
189
|
def reset_password_email_link
|
|
@@ -192,14 +196,6 @@ module Rodauth
|
|
|
192
196
|
ds.get(reset_password_key_column)
|
|
193
197
|
end
|
|
194
198
|
|
|
195
|
-
def login_form_footer
|
|
196
|
-
super + reset_password_request_link
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def reset_password_request_link
|
|
200
|
-
"<p><a href=\"#{prefix}/#{reset_password_request_route}\">Forgot Password?</a></p>"
|
|
201
|
-
end
|
|
202
|
-
|
|
203
199
|
def set_reset_password_email_last_sent
|
|
204
200
|
password_reset_ds.update(reset_password_email_last_sent_column=>Sequel::CURRENT_TIMESTAMP) if reset_password_email_last_sent_column
|
|
205
201
|
end
|
|
@@ -214,6 +210,10 @@ module Rodauth
|
|
|
214
210
|
|
|
215
211
|
private
|
|
216
212
|
|
|
213
|
+
def _login_form_footer_links
|
|
214
|
+
super << [20, reset_password_request_path, reset_password_request_link_text]
|
|
215
|
+
end
|
|
216
|
+
|
|
217
217
|
def reset_password_email_recently_sent?
|
|
218
218
|
(email_last_sent = get_reset_password_email_last_sent) && (Time.now - email_last_sent < reset_password_skip_resend_email_within)
|
|
219
219
|
end
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module Rodauth
|
|
4
4
|
Feature.define(:session_expiration, :SessionExpiration) do
|
|
5
|
-
error_flash "This session has expired, please login again
|
|
5
|
+
error_flash "This session has expired, please login again"
|
|
6
6
|
|
|
7
7
|
auth_value_method :max_session_lifetime, 86400
|
|
8
8
|
session_key :session_created_session_key, :session_created_at
|
|
9
|
+
auth_value_method :session_expiration_error_status, 401
|
|
9
10
|
auth_value_method :session_expiration_default, true
|
|
10
11
|
auth_value_method :session_inactivity_timeout, 1800
|
|
11
12
|
session_key :session_last_activity_session_key, :last_session_activity_at
|
|
@@ -37,6 +38,7 @@ module Rodauth
|
|
|
37
38
|
|
|
38
39
|
def expire_session
|
|
39
40
|
clear_session
|
|
41
|
+
set_redirect_error_status session_expiration_error_status
|
|
40
42
|
set_redirect_error_flash session_expiration_error_flash
|
|
41
43
|
redirect session_expiration_redirect
|
|
42
44
|
end
|
|
@@ -45,11 +47,11 @@ module Rodauth
|
|
|
45
47
|
require_login_redirect
|
|
46
48
|
end
|
|
47
49
|
|
|
48
|
-
private
|
|
49
|
-
|
|
50
50
|
def update_session
|
|
51
51
|
super
|
|
52
|
-
|
|
52
|
+
t = Time.now.to_i
|
|
53
|
+
set_session_value(session_last_activity_session_key, t)
|
|
54
|
+
set_session_value(session_created_session_key, t)
|
|
53
55
|
end
|
|
54
56
|
end
|
|
55
57
|
end
|
|
@@ -6,6 +6,7 @@ module Rodauth
|
|
|
6
6
|
redirect
|
|
7
7
|
|
|
8
8
|
auth_value_method :allow_raw_single_session_key?, false
|
|
9
|
+
auth_value_method :inactive_session_error_status, 401
|
|
9
10
|
auth_value_method :single_session_id_column, :id
|
|
10
11
|
auth_value_method :single_session_key_column, :key
|
|
11
12
|
session_key :single_session_session_key, :single_session_key
|
|
@@ -55,6 +56,7 @@ module Rodauth
|
|
|
55
56
|
|
|
56
57
|
def no_longer_active_session
|
|
57
58
|
clear_session
|
|
59
|
+
set_redirect_error_status inactive_session_error_status
|
|
58
60
|
set_redirect_error_flash single_session_error_flash
|
|
59
61
|
redirect single_session_redirect
|
|
60
62
|
end
|
|
@@ -70,6 +72,11 @@ module Rodauth
|
|
|
70
72
|
end
|
|
71
73
|
end
|
|
72
74
|
|
|
75
|
+
def update_session
|
|
76
|
+
super
|
|
77
|
+
update_single_session_key
|
|
78
|
+
end
|
|
79
|
+
|
|
73
80
|
private
|
|
74
81
|
|
|
75
82
|
def after_close_account
|
|
@@ -78,7 +85,7 @@ module Rodauth
|
|
|
78
85
|
end
|
|
79
86
|
|
|
80
87
|
def before_logout
|
|
81
|
-
reset_single_session_key
|
|
88
|
+
reset_single_session_key
|
|
82
89
|
super if defined?(super)
|
|
83
90
|
end
|
|
84
91
|
|
|
@@ -87,11 +94,6 @@ module Rodauth
|
|
|
87
94
|
set_session_value(single_session_session_key, data)
|
|
88
95
|
end
|
|
89
96
|
|
|
90
|
-
def update_session
|
|
91
|
-
super
|
|
92
|
-
update_single_session_key
|
|
93
|
-
end
|
|
94
|
-
|
|
95
97
|
def single_session_ds
|
|
96
98
|
db[single_session_table].
|
|
97
99
|
where(single_session_id_column=>session_value)
|
|
@@ -28,28 +28,32 @@ module Rodauth
|
|
|
28
28
|
button 'Send SMS Code', 'sms_request'
|
|
29
29
|
button 'Setup SMS Backup Number', 'sms_setup'
|
|
30
30
|
|
|
31
|
-
error_flash "Error authenticating via SMS code
|
|
31
|
+
error_flash "Error authenticating via SMS code", 'sms_invalid_code'
|
|
32
32
|
error_flash "Error disabling SMS authentication", 'sms_disable'
|
|
33
33
|
error_flash "Error setting up SMS authentication", 'sms_setup'
|
|
34
|
-
error_flash "Invalid or out of date SMS confirmation code used, must setup SMS authentication again
|
|
34
|
+
error_flash "Invalid or out of date SMS confirmation code used, must setup SMS authentication again", 'sms_invalid_confirmation_code'
|
|
35
35
|
error_flash "No current SMS code for this account", 'no_current_sms_code'
|
|
36
|
-
error_flash "SMS authentication has been locked out
|
|
37
|
-
error_flash "SMS authentication has already been setup
|
|
38
|
-
error_flash "SMS authentication has not been setup yet
|
|
39
|
-
error_flash "SMS authentication needs confirmation
|
|
36
|
+
error_flash "SMS authentication has been locked out", 'sms_lockout'
|
|
37
|
+
error_flash "SMS authentication has already been setup", 'sms_already_setup'
|
|
38
|
+
error_flash "SMS authentication has not been setup yet", 'sms_not_setup'
|
|
39
|
+
error_flash "SMS authentication needs confirmation", 'sms_needs_confirmation'
|
|
40
40
|
|
|
41
|
-
notice_flash "SMS authentication code has been sent
|
|
42
|
-
notice_flash "SMS authentication has been disabled
|
|
43
|
-
notice_flash "SMS authentication has been setup
|
|
41
|
+
notice_flash "SMS authentication code has been sent", 'sms_request'
|
|
42
|
+
notice_flash "SMS authentication has been disabled", 'sms_disable'
|
|
43
|
+
notice_flash "SMS authentication has been setup", 'sms_confirm'
|
|
44
|
+
|
|
45
|
+
translatable_method :sms_auth_link_text, "Authenticate Using SMS Code"
|
|
46
|
+
translatable_method :sms_setup_link_text, "Setup Backup SMS Authentication"
|
|
47
|
+
translatable_method :sms_disable_link_text, "Disable SMS Authentication"
|
|
44
48
|
|
|
45
49
|
redirect :sms_already_setup
|
|
46
50
|
redirect :sms_confirm
|
|
47
51
|
redirect :sms_disable
|
|
48
|
-
redirect(:sms_auth){
|
|
49
|
-
redirect(:sms_needs_confirmation){
|
|
50
|
-
redirect(:sms_needs_setup){
|
|
51
|
-
redirect(:sms_request){
|
|
52
|
-
redirect(:sms_lockout){
|
|
52
|
+
redirect(:sms_auth){sms_auth_path}
|
|
53
|
+
redirect(:sms_needs_confirmation){sms_confirm_path}
|
|
54
|
+
redirect(:sms_needs_setup){sms_setup_path}
|
|
55
|
+
redirect(:sms_request){sms_request_path}
|
|
56
|
+
redirect(:sms_lockout){two_factor_auth_required_redirect}
|
|
53
57
|
|
|
54
58
|
loaded_templates %w'sms-auth sms-confirm sms-disable sms-request sms-setup sms-code-field password-field'
|
|
55
59
|
view 'sms-auth', 'Authenticate via SMS Code', 'sms_auth'
|
|
@@ -64,18 +68,19 @@ module Rodauth
|
|
|
64
68
|
auth_value_method :sms_auth_code_length, 6
|
|
65
69
|
auth_value_method :sms_code_allowed_seconds, 300
|
|
66
70
|
auth_value_method :sms_code_column, :code
|
|
67
|
-
|
|
71
|
+
translatable_method :sms_code_label, 'SMS Code'
|
|
68
72
|
auth_value_method :sms_code_param, 'sms-code'
|
|
69
73
|
auth_value_method :sms_codes_table, :account_sms_codes
|
|
70
74
|
auth_value_method :sms_confirm_code_length, 12
|
|
71
75
|
auth_value_method :sms_failure_limit, 5
|
|
72
76
|
auth_value_method :sms_failures_column, :num_failures
|
|
73
77
|
auth_value_method :sms_id_column, :id
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
translatable_method :sms_invalid_code_message, "invalid SMS code"
|
|
79
|
+
translatable_method :sms_invalid_phone_message, "invalid SMS phone number"
|
|
76
80
|
auth_value_method :sms_issued_at_column, :code_issued_at
|
|
77
81
|
auth_value_method :sms_phone_column, :phone_number
|
|
78
|
-
|
|
82
|
+
translatable_method :sms_phone_label, 'Phone Number'
|
|
83
|
+
auth_value_method :sms_phone_input_type, 'tel'
|
|
79
84
|
auth_value_method :sms_phone_min_length, 7
|
|
80
85
|
auth_value_method :sms_phone_param, 'sms-phone'
|
|
81
86
|
|
|
@@ -110,7 +115,7 @@ module Rodauth
|
|
|
110
115
|
route(:sms_request) do |r|
|
|
111
116
|
require_login
|
|
112
117
|
require_account_session
|
|
113
|
-
require_two_factor_not_authenticated
|
|
118
|
+
require_two_factor_not_authenticated('sms_code')
|
|
114
119
|
require_sms_available
|
|
115
120
|
before_sms_request_route
|
|
116
121
|
|
|
@@ -133,7 +138,7 @@ module Rodauth
|
|
|
133
138
|
route(:sms_auth) do |r|
|
|
134
139
|
require_login
|
|
135
140
|
require_account_session
|
|
136
|
-
require_two_factor_not_authenticated
|
|
141
|
+
require_two_factor_not_authenticated('sms_code')
|
|
137
142
|
require_sms_available
|
|
138
143
|
|
|
139
144
|
unless sms_current_auth?
|
|
@@ -157,7 +162,7 @@ module Rodauth
|
|
|
157
162
|
if sms_code_match?(param(sms_code_param))
|
|
158
163
|
before_sms_auth
|
|
159
164
|
sms_remove_failures
|
|
160
|
-
two_factor_authenticate(
|
|
165
|
+
two_factor_authenticate('sms_code')
|
|
161
166
|
else
|
|
162
167
|
sms_record_failure
|
|
163
168
|
after_sms_failure
|
|
@@ -238,8 +243,8 @@ module Rodauth
|
|
|
238
243
|
before_sms_confirm
|
|
239
244
|
sms_confirm
|
|
240
245
|
after_sms_confirm
|
|
241
|
-
|
|
242
|
-
|
|
246
|
+
unless two_factor_authenticated?
|
|
247
|
+
two_factor_update_session('sms_code')
|
|
243
248
|
end
|
|
244
249
|
end
|
|
245
250
|
|
|
@@ -268,8 +273,8 @@ module Rodauth
|
|
|
268
273
|
transaction do
|
|
269
274
|
before_sms_disable
|
|
270
275
|
sms_disable
|
|
271
|
-
if
|
|
272
|
-
two_factor_remove_session
|
|
276
|
+
if two_factor_login_type_match?('sms_code')
|
|
277
|
+
two_factor_remove_session('sms_code')
|
|
273
278
|
end
|
|
274
279
|
after_sms_disable
|
|
275
280
|
end
|
|
@@ -284,18 +289,6 @@ module Rodauth
|
|
|
284
289
|
end
|
|
285
290
|
end
|
|
286
291
|
|
|
287
|
-
def two_factor_need_setup_redirect
|
|
288
|
-
super || (sms_needs_setup_redirect if sms_codes_primary?)
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
def two_factor_auth_required_redirect
|
|
292
|
-
super || (sms_request_redirect if sms_codes_primary? && sms_available?)
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
def two_factor_auth_fallback_redirect
|
|
296
|
-
sms_available? ? sms_request_redirect : super
|
|
297
|
-
end
|
|
298
|
-
|
|
299
292
|
def two_factor_remove
|
|
300
293
|
super
|
|
301
294
|
sms_disable
|
|
@@ -306,37 +299,6 @@ module Rodauth
|
|
|
306
299
|
sms_remove_failures
|
|
307
300
|
end
|
|
308
301
|
|
|
309
|
-
def two_factor_authentication_setup?
|
|
310
|
-
super || (sms_codes_primary? && sms_setup?)
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
def otp_auth_form_footer
|
|
314
|
-
"#{super if defined?(super)}#{"<p><a href=\"#{sms_request_route}\">Authenticate using SMS code</a></p>" if sms_available?}"
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
def otp_lockout_redirect
|
|
318
|
-
if sms_available?
|
|
319
|
-
sms_request_redirect
|
|
320
|
-
else
|
|
321
|
-
super if defined?(super)
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
def otp_lockout_error_flash
|
|
326
|
-
msg = super if defined?(super)
|
|
327
|
-
if sms_available?
|
|
328
|
-
msg = "#{msg} Can use SMS code to unlock."
|
|
329
|
-
end
|
|
330
|
-
msg
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
def otp_remove
|
|
334
|
-
super if defined?(super)
|
|
335
|
-
unless sms_codes_primary?
|
|
336
|
-
sms_disable
|
|
337
|
-
end
|
|
338
|
-
end
|
|
339
|
-
|
|
340
302
|
def require_sms_setup
|
|
341
303
|
unless sms_setup?
|
|
342
304
|
set_redirect_error_status(two_factor_not_setup_error_status)
|
|
@@ -375,7 +337,6 @@ module Rodauth
|
|
|
375
337
|
def sms_disable
|
|
376
338
|
sms_ds.delete
|
|
377
339
|
@sms = nil
|
|
378
|
-
super if defined?(super)
|
|
379
340
|
end
|
|
380
341
|
|
|
381
342
|
def sms_confirm_failure
|
|
@@ -415,11 +376,11 @@ module Rodauth
|
|
|
415
376
|
end
|
|
416
377
|
|
|
417
378
|
def sms_auth_message(code)
|
|
418
|
-
"SMS authentication code for #{
|
|
379
|
+
"SMS authentication code for #{domain} is #{code}"
|
|
419
380
|
end
|
|
420
381
|
|
|
421
382
|
def sms_confirm_message(code)
|
|
422
|
-
"SMS confirmation code for #{
|
|
383
|
+
"SMS confirmation code for #{domain} is #{code}"
|
|
423
384
|
end
|
|
424
385
|
|
|
425
386
|
def sms_set_code(code)
|
|
@@ -468,10 +429,39 @@ module Rodauth
|
|
|
468
429
|
sms_code && sms_code_issued_at + sms_code_allowed_seconds > Time.now
|
|
469
430
|
end
|
|
470
431
|
|
|
432
|
+
def possible_authentication_methods
|
|
433
|
+
methods = super
|
|
434
|
+
methods << 'sms_code' if sms_setup?
|
|
435
|
+
methods
|
|
436
|
+
end
|
|
437
|
+
|
|
471
438
|
private
|
|
472
439
|
|
|
440
|
+
def _two_factor_auth_links
|
|
441
|
+
links = super
|
|
442
|
+
links << [30, sms_request_path, sms_auth_link_text] if sms_available?
|
|
443
|
+
links
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
def _two_factor_setup_links
|
|
447
|
+
links = super
|
|
448
|
+
links << [30, sms_setup_path, sms_setup_link_text] if !sms_setup? && (sms_codes_primary? || uses_two_factor_authentication?)
|
|
449
|
+
links
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def _two_factor_remove_links
|
|
453
|
+
links = super
|
|
454
|
+
links << [30, sms_disable_path, sms_disable_link_text] if sms_setup?
|
|
455
|
+
links
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
def _two_factor_remove_all_from_session
|
|
459
|
+
two_factor_remove_session('sms_codes')
|
|
460
|
+
super
|
|
461
|
+
end
|
|
462
|
+
|
|
473
463
|
def sms_codes_primary?
|
|
474
|
-
|
|
464
|
+
(features & [:otp, :webauthn]).empty?
|
|
475
465
|
end
|
|
476
466
|
|
|
477
467
|
def sms_normalize_phone(phone)
|