rodauth 1.22.0 → 2.3.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.
Files changed (198) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +190 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +210 -80
  5. data/doc/account_expiration.rdoc +12 -26
  6. data/doc/active_sessions.rdoc +49 -0
  7. data/doc/audit_logging.rdoc +44 -0
  8. data/doc/base.rdoc +75 -128
  9. data/doc/change_login.rdoc +7 -14
  10. data/doc/change_password.rdoc +9 -13
  11. data/doc/change_password_notify.rdoc +2 -2
  12. data/doc/close_account.rdoc +9 -16
  13. data/doc/confirm_password.rdoc +12 -5
  14. data/doc/create_account.rdoc +11 -22
  15. data/doc/disallow_password_reuse.rdoc +6 -13
  16. data/doc/email_auth.rdoc +15 -14
  17. data/doc/email_base.rdoc +6 -15
  18. data/doc/guides/admin_activation.rdoc +46 -0
  19. data/doc/guides/already_authenticated.rdoc +10 -0
  20. data/doc/guides/alternative_login.rdoc +46 -0
  21. data/doc/guides/create_account_programmatically.rdoc +38 -0
  22. data/doc/guides/delay_password.rdoc +25 -0
  23. data/doc/guides/email_only.rdoc +16 -0
  24. data/doc/guides/i18n.rdoc +26 -0
  25. data/doc/{internals.rdoc → guides/internals.rdoc} +0 -0
  26. data/doc/guides/links.rdoc +12 -0
  27. data/doc/guides/login_return.rdoc +37 -0
  28. data/doc/guides/password_column.rdoc +25 -0
  29. data/doc/guides/password_confirmation.rdoc +37 -0
  30. data/doc/guides/password_requirements.rdoc +30 -0
  31. data/doc/guides/paths.rdoc +36 -0
  32. data/doc/guides/query_params.rdoc +9 -0
  33. data/doc/guides/redirects.rdoc +17 -0
  34. data/doc/guides/registration_field.rdoc +68 -0
  35. data/doc/guides/require_mfa.rdoc +30 -0
  36. data/doc/guides/reset_password_autologin.rdoc +21 -0
  37. data/doc/guides/status_column.rdoc +28 -0
  38. data/doc/guides/totp_or_recovery.rdoc +16 -0
  39. data/doc/http_basic_auth.rdoc +10 -1
  40. data/doc/jwt.rdoc +22 -22
  41. data/doc/jwt_cors.rdoc +2 -3
  42. data/doc/jwt_refresh.rdoc +23 -8
  43. data/doc/lockout.rdoc +17 -15
  44. data/doc/login.rdoc +17 -2
  45. data/doc/login_password_requirements_base.rdoc +18 -37
  46. data/doc/logout.rdoc +2 -2
  47. data/doc/otp.rdoc +25 -19
  48. data/doc/password_complexity.rdoc +10 -26
  49. data/doc/password_expiration.rdoc +11 -25
  50. data/doc/password_grace_period.rdoc +16 -2
  51. data/doc/recovery_codes.rdoc +18 -12
  52. data/doc/release_notes/1.23.0.txt +32 -0
  53. data/doc/release_notes/2.0.0.txt +361 -0
  54. data/doc/release_notes/2.1.0.txt +31 -0
  55. data/doc/release_notes/2.2.0.txt +39 -0
  56. data/doc/release_notes/2.3.0.txt +37 -0
  57. data/doc/remember.rdoc +40 -64
  58. data/doc/reset_password.rdoc +12 -9
  59. data/doc/session_expiration.rdoc +1 -0
  60. data/doc/single_session.rdoc +16 -25
  61. data/doc/sms_codes.rdoc +24 -14
  62. data/doc/two_factor_base.rdoc +60 -22
  63. data/doc/verify_account.rdoc +14 -12
  64. data/doc/verify_account_grace_period.rdoc +6 -2
  65. data/doc/verify_login_change.rdoc +9 -8
  66. data/doc/webauthn.rdoc +115 -0
  67. data/doc/webauthn_login.rdoc +15 -0
  68. data/doc/webauthn_verify_account.rdoc +9 -0
  69. data/javascript/webauthn_auth.js +45 -0
  70. data/javascript/webauthn_setup.js +35 -0
  71. data/lib/roda/plugins/rodauth.rb +1 -1
  72. data/lib/rodauth.rb +36 -28
  73. data/lib/rodauth/features/account_expiration.rb +5 -5
  74. data/lib/rodauth/features/active_sessions.rb +158 -0
  75. data/lib/rodauth/features/audit_logging.rb +98 -0
  76. data/lib/rodauth/features/base.rb +144 -43
  77. data/lib/rodauth/features/change_password_notify.rb +2 -2
  78. data/lib/rodauth/features/close_account.rb +8 -6
  79. data/lib/rodauth/features/confirm_password.rb +40 -2
  80. data/lib/rodauth/features/create_account.rb +8 -13
  81. data/lib/rodauth/features/disallow_common_passwords.rb +1 -1
  82. data/lib/rodauth/features/disallow_password_reuse.rb +1 -1
  83. data/lib/rodauth/features/email_auth.rb +31 -30
  84. data/lib/rodauth/features/email_base.rb +9 -4
  85. data/lib/rodauth/features/http_basic_auth.rb +55 -35
  86. data/lib/rodauth/features/jwt.rb +63 -16
  87. data/lib/rodauth/features/jwt_cors.rb +15 -15
  88. data/lib/rodauth/features/jwt_refresh.rb +42 -13
  89. data/lib/rodauth/features/lockout.rb +12 -14
  90. data/lib/rodauth/features/login.rb +64 -15
  91. data/lib/rodauth/features/login_password_requirements_base.rb +13 -8
  92. data/lib/rodauth/features/otp.rb +77 -80
  93. data/lib/rodauth/features/password_complexity.rb +8 -13
  94. data/lib/rodauth/features/password_expiration.rb +2 -2
  95. data/lib/rodauth/features/password_grace_period.rb +17 -10
  96. data/lib/rodauth/features/recovery_codes.rb +49 -53
  97. data/lib/rodauth/features/remember.rb +11 -27
  98. data/lib/rodauth/features/reset_password.rb +26 -26
  99. data/lib/rodauth/features/session_expiration.rb +7 -10
  100. data/lib/rodauth/features/single_session.rb +8 -6
  101. data/lib/rodauth/features/sms_codes.rb +62 -72
  102. data/lib/rodauth/features/two_factor_base.rb +134 -30
  103. data/lib/rodauth/features/verify_account.rb +29 -21
  104. data/lib/rodauth/features/verify_account_grace_period.rb +18 -9
  105. data/lib/rodauth/features/verify_login_change.rb +12 -11
  106. data/lib/rodauth/features/webauthn.rb +505 -0
  107. data/lib/rodauth/features/webauthn_login.rb +70 -0
  108. data/lib/rodauth/features/webauthn_verify_account.rb +46 -0
  109. data/lib/rodauth/migrations.rb +16 -5
  110. data/lib/rodauth/version.rb +2 -2
  111. data/templates/button.str +1 -3
  112. data/templates/change-login.str +1 -2
  113. data/templates/change-password.str +3 -5
  114. data/templates/close-account.str +2 -2
  115. data/templates/confirm-password.str +1 -1
  116. data/templates/create-account.str +1 -1
  117. data/templates/email-auth-request-form.str +2 -3
  118. data/templates/email-auth.str +1 -1
  119. data/templates/global-logout-field.str +6 -0
  120. data/templates/login-confirm-field.str +2 -4
  121. data/templates/login-display.str +3 -2
  122. data/templates/login-field.str +2 -4
  123. data/templates/login-form-footer.str +6 -0
  124. data/templates/login-form.str +7 -0
  125. data/templates/login.str +1 -9
  126. data/templates/logout.str +1 -1
  127. data/templates/multi-phase-login.str +3 -0
  128. data/templates/otp-auth-code-field.str +5 -3
  129. data/templates/otp-auth.str +1 -1
  130. data/templates/otp-disable.str +1 -1
  131. data/templates/otp-setup.str +3 -3
  132. data/templates/password-confirm-field.str +2 -4
  133. data/templates/password-field.str +2 -4
  134. data/templates/recovery-auth.str +3 -6
  135. data/templates/recovery-codes.str +1 -1
  136. data/templates/remember.str +15 -20
  137. data/templates/reset-password-request.str +3 -3
  138. data/templates/reset-password.str +1 -2
  139. data/templates/sms-auth.str +1 -1
  140. data/templates/sms-code-field.str +5 -3
  141. data/templates/sms-confirm.str +1 -2
  142. data/templates/sms-disable.str +1 -2
  143. data/templates/sms-request.str +1 -1
  144. data/templates/sms-setup.str +6 -4
  145. data/templates/two-factor-auth.str +5 -0
  146. data/templates/two-factor-disable.str +6 -0
  147. data/templates/two-factor-manage.str +16 -0
  148. data/templates/unlock-account-request.str +4 -4
  149. data/templates/unlock-account.str +1 -1
  150. data/templates/verify-account-resend.str +3 -3
  151. data/templates/verify-account.str +1 -2
  152. data/templates/verify-login-change.str +1 -1
  153. data/templates/webauthn-auth.str +11 -0
  154. data/templates/webauthn-remove.str +14 -0
  155. data/templates/webauthn-setup.str +12 -0
  156. metadata +94 -54
  157. data/Rakefile +0 -179
  158. data/doc/verify_change_login.rdoc +0 -11
  159. data/lib/rodauth/features/verify_change_login.rb +0 -20
  160. data/spec/account_expiration_spec.rb +0 -225
  161. data/spec/all.rb +0 -1
  162. data/spec/change_login_spec.rb +0 -156
  163. data/spec/change_password_notify_spec.rb +0 -33
  164. data/spec/change_password_spec.rb +0 -202
  165. data/spec/close_account_spec.rb +0 -162
  166. data/spec/confirm_password_spec.rb +0 -70
  167. data/spec/create_account_spec.rb +0 -127
  168. data/spec/disallow_common_passwords_spec.rb +0 -93
  169. data/spec/disallow_password_reuse_spec.rb +0 -179
  170. data/spec/email_auth_spec.rb +0 -285
  171. data/spec/http_basic_auth_spec.rb +0 -143
  172. data/spec/jwt_cors_spec.rb +0 -57
  173. data/spec/jwt_refresh_spec.rb +0 -256
  174. data/spec/jwt_spec.rb +0 -235
  175. data/spec/lockout_spec.rb +0 -250
  176. data/spec/login_spec.rb +0 -328
  177. data/spec/migrate/001_tables.rb +0 -184
  178. data/spec/migrate/002_account_password_hash_column.rb +0 -11
  179. data/spec/migrate_password/001_tables.rb +0 -73
  180. data/spec/migrate_travis/001_tables.rb +0 -141
  181. data/spec/password_complexity_spec.rb +0 -109
  182. data/spec/password_expiration_spec.rb +0 -244
  183. data/spec/password_grace_period_spec.rb +0 -93
  184. data/spec/remember_spec.rb +0 -451
  185. data/spec/reset_password_spec.rb +0 -229
  186. data/spec/rodauth_spec.rb +0 -343
  187. data/spec/session_expiration_spec.rb +0 -58
  188. data/spec/single_session_spec.rb +0 -127
  189. data/spec/spec_helper.rb +0 -327
  190. data/spec/two_factor_spec.rb +0 -1462
  191. data/spec/update_password_hash_spec.rb +0 -40
  192. data/spec/verify_account_grace_period_spec.rb +0 -171
  193. data/spec/verify_account_spec.rb +0 -240
  194. data/spec/verify_change_login_spec.rb +0 -46
  195. data/spec/verify_login_change_spec.rb +0 -232
  196. data/spec/views/layout-other.str +0 -11
  197. data/spec/views/layout.str +0 -11
  198. data/spec/views/login.str +0 -21
@@ -17,14 +17,14 @@ module Rodauth
17
17
  button 'Authenticate via Recovery Code', 'recovery_auth'
18
18
  button 'View Authentication Recovery Codes', 'view_recovery_codes'
19
19
 
20
- error_flash "Error authenticating via recovery code.", 'invalid_recovery_code'
21
- error_flash "Unable to add recovery codes.", 'add_recovery_codes'
22
- error_flash "Unable to view recovery codes.", 'view_recovery_codes'
20
+ error_flash "Error authenticating via recovery code", 'invalid_recovery_code'
21
+ error_flash "Unable to add recovery codes", 'add_recovery_codes'
22
+ error_flash "Unable to view recovery codes", 'view_recovery_codes'
23
23
 
24
- notice_flash "Additional authentication recovery codes have been added.", 'recovery_codes_added'
24
+ notice_flash "Additional authentication recovery codes have been added", 'recovery_codes_added'
25
25
 
26
- redirect(:recovery_auth){"#{prefix}/#{recovery_auth_route}"}
27
- redirect(:add_recovery_codes){"#{prefix}/#{recovery_codes_route}"}
26
+ redirect(:recovery_auth){recovery_auth_path}
27
+ redirect(:add_recovery_codes){recovery_codes_path}
28
28
 
29
29
  loaded_templates %w'add-recovery-codes recovery-auth recovery-codes password-field'
30
30
  view 'add-recovery-codes', 'Authentication Recovery Codes', 'add_recovery_codes'
@@ -32,15 +32,19 @@ module Rodauth
32
32
  view 'recovery-codes', 'View Authentication Recovery Codes', 'recovery_codes'
33
33
 
34
34
  auth_value_method :add_recovery_codes_param, 'add'
35
- auth_value_method :add_recovery_codes_heading, '<h2>Add Additional Recovery Codes</h2>'
36
- auth_value_method :invalid_recovery_code_message, "Invalid recovery code"
35
+ translatable_method :add_recovery_codes_heading, '<h2>Add Additional Recovery Codes</h2>'
36
+ auth_value_method :auto_add_recovery_codes?, false
37
+ translatable_method :invalid_recovery_code_message, "Invalid recovery code"
37
38
  auth_value_method :recovery_codes_limit, 16
38
39
  auth_value_method :recovery_codes_column, :code
39
40
  auth_value_method :recovery_codes_id_column, :id
40
- auth_value_method :recovery_codes_label, 'Recovery Code'
41
+ translatable_method :recovery_codes_label, 'Recovery Code'
41
42
  auth_value_method :recovery_codes_param, 'recovery-code'
42
43
  auth_value_method :recovery_codes_table, :account_recovery_codes
43
44
 
45
+ translatable_method :recovery_auth_link_text, "Authenticate Using Recovery Code"
46
+ translatable_method :recovery_codes_link_text, "View Authentication Recovery Codes"
47
+
44
48
  auth_cached_method :recovery_codes
45
49
 
46
50
  auth_value_methods(
@@ -59,7 +63,7 @@ module Rodauth
59
63
  require_login
60
64
  require_account_session
61
65
  require_two_factor_setup
62
- require_two_factor_not_authenticated
66
+ require_two_factor_not_authenticated('recovery_code')
63
67
  before_recovery_auth_route
64
68
 
65
69
  r.get do
@@ -69,7 +73,7 @@ module Rodauth
69
73
  r.post do
70
74
  if recovery_code_match?(param(recovery_codes_param))
71
75
  before_recovery_auth
72
- two_factor_authenticate(:recovery_code)
76
+ two_factor_authenticate('recovery_code')
73
77
  end
74
78
 
75
79
  set_response_error_status(invalid_key_error_status)
@@ -124,61 +128,24 @@ module Rodauth
124
128
 
125
129
  attr_accessor :recovery_codes_button
126
130
 
127
- def two_factor_need_setup_redirect
128
- super || (add_recovery_codes_redirect if recovery_codes_primary?)
129
- end
130
-
131
- def two_factor_auth_required_redirect
132
- super || (recovery_auth_redirect if recovery_codes_primary?)
133
- end
134
-
135
- def two_factor_auth_fallback_redirect
136
- recovery_auth_redirect
137
- end
138
-
139
131
  def two_factor_remove
140
132
  super
141
133
  recovery_codes_remove
142
134
  end
143
135
 
144
- def two_factor_authentication_setup?
145
- super || (recovery_codes_primary? && !recovery_codes.empty?)
146
- end
147
-
148
- def otp_auth_form_footer
149
- "#{super if defined?(super)}<p><a href=\"#{recovery_auth_route}\">Authenticate using recovery code</a></p>"
150
- end
151
-
152
- def otp_lockout_redirect
153
- recovery_auth_redirect
154
- end
155
-
156
- def otp_lockout_error_flash
157
- "#{super if defined?(super)} Can use recovery code to unlock."
158
- end
159
-
160
136
  def otp_add_key
161
137
  super if defined?(super)
162
- add_recovery_codes(recovery_codes_limit - recovery_codes.length)
138
+ auto_add_missing_recovery_codes
163
139
  end
164
140
 
165
141
  def sms_confirm
166
142
  super if defined?(super)
167
- add_recovery_codes(recovery_codes_limit - recovery_codes.length)
168
- end
169
-
170
- def otp_remove
171
- super if defined?(super)
172
- unless recovery_codes_primary?
173
- recovery_codes_remove
174
- end
143
+ auto_add_missing_recovery_codes
175
144
  end
176
145
 
177
- def sms_disable
146
+ def add_webauthn_credential(_)
178
147
  super if defined?(super)
179
- unless recovery_codes_primary?
180
- recovery_codes_remove
181
- end
148
+ auto_add_missing_recovery_codes
182
149
  end
183
150
 
184
151
  def recovery_codes_remove
@@ -221,14 +188,43 @@ module Rodauth
221
188
  end
222
189
  end
223
190
 
191
+ def possible_authentication_methods
192
+ methods = super
193
+ methods << 'recovery_code' unless recovery_codes_ds.empty?
194
+ methods
195
+ end
196
+
224
197
  private
225
198
 
199
+ def _two_factor_auth_links
200
+ links = super
201
+ links << [40, recovery_auth_path, recovery_auth_link_text] unless recovery_codes_ds.empty?
202
+ links
203
+ end
204
+
205
+ def _two_factor_setup_links
206
+ links = super
207
+ links << [40, recovery_codes_path, recovery_codes_link_text] if (recovery_codes_primary? || uses_two_factor_authentication?)
208
+ links
209
+ end
210
+
211
+ def _two_factor_remove_all_from_session
212
+ two_factor_remove_session('recovery_code')
213
+ super
214
+ end
215
+
226
216
  def new_recovery_code
227
217
  random_key
228
218
  end
229
219
 
230
220
  def recovery_codes_primary?
231
- (features & [:otp, :sms_codes]).empty?
221
+ (features & [:otp, :sms_codes, :webauthn]).empty?
222
+ end
223
+
224
+ def auto_add_missing_recovery_codes
225
+ if auto_add_recovery_codes?
226
+ add_recovery_codes(recovery_codes_limit - recovery_codes.length)
227
+ end
232
228
  end
233
229
 
234
230
  def _recovery_codes
@@ -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
- session_key :remembered_session_key, :remembered
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
- auth_value_method :remember_remember_label, 'Remember Me'
35
- auth_value_method :remember_forget_label, 'Forget Me'
36
- auth_value_method :remember_disable_label, 'Disable Remember Me'
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
- session[session_key] = id
108
+ set_session_value(session_key, id)
113
109
  account = account_from_session
114
- session.delete(session_key)
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
- update_session
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
- key = remember_key_value
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
- !!session[remembered_session_key]
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
- auth_value_method :reset_password_email_subject, 'Reset Password'
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, nil
39
- auth_value_method :reset_password_explanatory_text, "<p>If you have forgotten your password, you can request a password reset:</p>"
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
- if account_from_login(param(login_param)) && open_account?
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
- else
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
- redirect reset_password_email_sent_redirect
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
- session[reset_password_session_key] = key
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
- session[reset_password_session_key] = nil
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
- update_session
151
+ autologin_session('reset_password')
148
152
  end
149
153
 
150
- session[reset_password_session_key] = nil
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.deliver!
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,16 +2,16 @@
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
+ redirect{require_login_redirect}
6
7
 
7
8
  auth_value_method :max_session_lifetime, 86400
8
9
  session_key :session_created_session_key, :session_created_at
10
+ auth_value_method :session_expiration_error_status, 401
9
11
  auth_value_method :session_expiration_default, true
10
12
  auth_value_method :session_inactivity_timeout, 1800
11
13
  session_key :session_last_activity_session_key, :last_session_activity_at
12
14
 
13
- auth_value_methods :session_expiration_redirect
14
-
15
15
  def check_session_expiration
16
16
  return unless logged_in?
17
17
 
@@ -37,19 +37,16 @@ module Rodauth
37
37
 
38
38
  def expire_session
39
39
  clear_session
40
+ set_redirect_error_status session_expiration_error_status
40
41
  set_redirect_error_flash session_expiration_error_flash
41
42
  redirect session_expiration_redirect
42
43
  end
43
44
 
44
- def session_expiration_redirect
45
- require_login_redirect
46
- end
47
-
48
- private
49
-
50
45
  def update_session
51
46
  super
52
- session[session_last_activity_session_key] = session[session_created_session_key] = Time.now.to_i
47
+ t = Time.now.to_i
48
+ set_session_value(session_last_activity_session_key, t)
49
+ set_session_value(session_created_session_key, t)
53
50
  end
54
51
  end
55
52
  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 if request.post?
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)