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.
Files changed (200) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +182 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +211 -79
  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 +22 -0
  42. data/doc/jwt_refresh.rdoc +18 -8
  43. data/doc/lockout.rdoc +17 -15
  44. data/doc/login.rdoc +10 -2
  45. data/doc/login_password_requirements_base.rdoc +15 -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.22.0.txt +11 -0
  53. data/doc/release_notes/1.23.0.txt +32 -0
  54. data/doc/release_notes/2.0.0.txt +361 -0
  55. data/doc/release_notes/2.1.0.txt +31 -0
  56. data/doc/release_notes/2.2.0.txt +39 -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/confirm_password.rb +40 -2
  79. data/lib/rodauth/features/create_account.rb +8 -13
  80. data/lib/rodauth/features/disallow_common_passwords.rb +1 -1
  81. data/lib/rodauth/features/disallow_password_reuse.rb +1 -1
  82. data/lib/rodauth/features/email_auth.rb +31 -30
  83. data/lib/rodauth/features/email_base.rb +9 -4
  84. data/lib/rodauth/features/http_basic_auth.rb +55 -35
  85. data/lib/rodauth/features/jwt.rb +63 -16
  86. data/lib/rodauth/features/jwt_cors.rb +53 -0
  87. data/lib/rodauth/features/jwt_refresh.rb +32 -9
  88. data/lib/rodauth/features/lockout.rb +12 -14
  89. data/lib/rodauth/features/login.rb +54 -10
  90. data/lib/rodauth/features/login_password_requirements_base.rb +4 -4
  91. data/lib/rodauth/features/otp.rb +77 -80
  92. data/lib/rodauth/features/password_complexity.rb +8 -13
  93. data/lib/rodauth/features/password_expiration.rb +2 -2
  94. data/lib/rodauth/features/password_grace_period.rb +17 -10
  95. data/lib/rodauth/features/recovery_codes.rb +49 -53
  96. data/lib/rodauth/features/remember.rb +11 -27
  97. data/lib/rodauth/features/reset_password.rb +26 -26
  98. data/lib/rodauth/features/session_expiration.rb +6 -4
  99. data/lib/rodauth/features/single_session.rb +8 -6
  100. data/lib/rodauth/features/sms_codes.rb +62 -72
  101. data/lib/rodauth/features/two_factor_base.rb +134 -30
  102. data/lib/rodauth/features/verify_account.rb +29 -21
  103. data/lib/rodauth/features/verify_account_grace_period.rb +18 -9
  104. data/lib/rodauth/features/verify_login_change.rb +12 -11
  105. data/lib/rodauth/features/webauthn.rb +505 -0
  106. data/lib/rodauth/features/webauthn_login.rb +70 -0
  107. data/lib/rodauth/features/webauthn_verify_account.rb +46 -0
  108. data/lib/rodauth/version.rb +2 -2
  109. data/templates/button.str +1 -3
  110. data/templates/change-login.str +1 -2
  111. data/templates/change-password.str +3 -5
  112. data/templates/close-account.str +2 -2
  113. data/templates/confirm-password.str +1 -1
  114. data/templates/create-account.str +1 -1
  115. data/templates/email-auth-email.str +1 -1
  116. data/templates/email-auth-request-form.str +2 -3
  117. data/templates/email-auth.str +1 -1
  118. data/templates/global-logout-field.str +6 -0
  119. data/templates/login-confirm-field.str +2 -4
  120. data/templates/login-display.str +3 -2
  121. data/templates/login-field.str +2 -4
  122. data/templates/login-form-footer.str +6 -0
  123. data/templates/login-form.str +7 -0
  124. data/templates/login.str +1 -9
  125. data/templates/logout.str +1 -1
  126. data/templates/multi-phase-login.str +3 -0
  127. data/templates/otp-auth-code-field.str +5 -3
  128. data/templates/otp-auth.str +1 -1
  129. data/templates/otp-disable.str +1 -1
  130. data/templates/otp-setup.str +3 -3
  131. data/templates/password-confirm-field.str +2 -4
  132. data/templates/password-field.str +2 -4
  133. data/templates/recovery-auth.str +3 -6
  134. data/templates/recovery-codes.str +1 -1
  135. data/templates/remember.str +15 -20
  136. data/templates/reset-password-email.str +1 -1
  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-email.str +1 -1
  149. data/templates/unlock-account-request.str +4 -4
  150. data/templates/unlock-account.str +1 -1
  151. data/templates/verify-account-email.str +1 -1
  152. data/templates/verify-account-resend.str +3 -3
  153. data/templates/verify-account.str +1 -2
  154. data/templates/verify-login-change-email.str +2 -1
  155. data/templates/verify-login-change.str +1 -1
  156. data/templates/webauthn-auth.str +11 -0
  157. data/templates/webauthn-remove.str +14 -0
  158. data/templates/webauthn-setup.str +12 -0
  159. metadata +110 -52
  160. data/Rakefile +0 -179
  161. data/doc/verify_change_login.rdoc +0 -11
  162. data/lib/rodauth/features/verify_change_login.rb +0 -20
  163. data/spec/account_expiration_spec.rb +0 -225
  164. data/spec/all.rb +0 -1
  165. data/spec/change_login_spec.rb +0 -156
  166. data/spec/change_password_notify_spec.rb +0 -33
  167. data/spec/change_password_spec.rb +0 -202
  168. data/spec/close_account_spec.rb +0 -162
  169. data/spec/confirm_password_spec.rb +0 -70
  170. data/spec/create_account_spec.rb +0 -127
  171. data/spec/disallow_common_passwords_spec.rb +0 -93
  172. data/spec/disallow_password_reuse_spec.rb +0 -179
  173. data/spec/email_auth_spec.rb +0 -285
  174. data/spec/http_basic_auth_spec.rb +0 -143
  175. data/spec/jwt_refresh_spec.rb +0 -256
  176. data/spec/jwt_spec.rb +0 -235
  177. data/spec/lockout_spec.rb +0 -250
  178. data/spec/login_spec.rb +0 -328
  179. data/spec/migrate/001_tables.rb +0 -184
  180. data/spec/migrate/002_account_password_hash_column.rb +0 -11
  181. data/spec/migrate_password/001_tables.rb +0 -73
  182. data/spec/migrate_travis/001_tables.rb +0 -141
  183. data/spec/password_complexity_spec.rb +0 -109
  184. data/spec/password_expiration_spec.rb +0 -244
  185. data/spec/password_grace_period_spec.rb +0 -93
  186. data/spec/remember_spec.rb +0 -451
  187. data/spec/reset_password_spec.rb +0 -229
  188. data/spec/rodauth_spec.rb +0 -343
  189. data/spec/session_expiration_spec.rb +0 -58
  190. data/spec/single_session_spec.rb +0 -127
  191. data/spec/spec_helper.rb +0 -327
  192. data/spec/two_factor_spec.rb +0 -1462
  193. data/spec/update_password_hash_spec.rb +0 -40
  194. data/spec/verify_account_grace_period_spec.rb +0 -171
  195. data/spec/verify_account_spec.rb +0 -240
  196. data/spec/verify_change_login_spec.rb +0 -46
  197. data/spec/verify_login_change_spec.rb +0 -232
  198. data/spec/views/layout-other.str +0 -11
  199. data/spec/views/layout.str +0 -11
  200. data/spec/views/login.str +0 -21
@@ -2,25 +2,50 @@
2
2
 
3
3
  module Rodauth
4
4
  Feature.define(:two_factor_base, :TwoFactorBase) do
5
+ loaded_templates %w'two-factor-manage two-factor-auth two-factor-disable'
6
+
7
+ view 'two-factor-manage', 'Manage Multifactor Authentication', 'two_factor_manage'
8
+ view 'two-factor-auth', 'Authenticate Using Additional Factor', 'two_factor_auth'
9
+ view 'two-factor-disable', 'Remove All Multifactor Authentication Methods', 'two_factor_disable'
10
+
11
+ before :two_factor_disable
12
+
5
13
  after :two_factor_authentication
14
+ after :two_factor_disable
15
+
16
+ additional_form_tags :two_factor_disable
17
+
18
+ button "Remove All Multifactor Authentication Methods", :two_factor_disable
6
19
 
7
- redirect :two_factor_auth
8
- redirect :two_factor_already_authenticated
20
+ redirect(:two_factor_auth)
21
+ redirect(:two_factor_already_authenticated)
22
+ redirect(:two_factor_disable)
23
+ redirect(:two_factor_need_setup){two_factor_manage_path}
24
+ redirect(:two_factor_auth_required){two_factor_auth_path}
9
25
 
10
- notice_flash "You have been authenticated via 2nd factor", "two_factor_auth"
26
+ notice_flash "You have been multifactor authenticated", "two_factor_auth"
27
+ notice_flash "All multifactor authentication methods have been disabled", "two_factor_disable"
11
28
 
12
- error_flash "This account has not been setup for two factor authentication", 'two_factor_not_setup'
13
- error_flash "Already authenticated via 2nd factor", 'two_factor_already_authenticated'
14
- error_flash "You need to authenticate via 2nd factor before continuing.", 'two_factor_need_authentication'
29
+ error_flash "This account has not been setup for multifactor authentication", 'two_factor_not_setup'
30
+ error_flash "You have already been multifactor authenticated", 'two_factor_already_authenticated'
31
+ error_flash "You need to authenticate via an additional factor before continuing", 'two_factor_need_authentication'
32
+ error_flash "Unable to remove all multifactor authentication methods", "two_factor_disable"
15
33
 
16
34
  auth_value_method :two_factor_already_authenticated_error_status, 403
17
35
  auth_value_method :two_factor_need_authentication_error_status, 401
18
36
  auth_value_method :two_factor_not_setup_error_status, 403
19
37
 
20
- session_key :two_factor_session_key, :two_factor_auth
21
38
  session_key :two_factor_setup_session_key, :two_factor_auth_setup
22
- auth_value_method :two_factor_need_setup_redirect, nil
23
- auth_value_method :two_factor_auth_required_redirect, nil
39
+ session_key :two_factor_auth_redirect_session_key, :two_factor_auth_redirect
40
+
41
+ translatable_method :two_factor_setup_heading, "<h2>Setup Multifactor Authentication</h2>"
42
+ translatable_method :two_factor_remove_heading, "<h2>Remove Multifactor Authentication</h2>"
43
+ translatable_method :two_factor_disable_link_text, "Remove All Multifactor Authentication Methods"
44
+ auth_value_method :two_factor_auth_return_to_requested_location?, false
45
+
46
+ auth_cached_method :two_factor_auth_links
47
+ auth_cached_method :two_factor_setup_links
48
+ auth_cached_method :two_factor_remove_links
24
49
 
25
50
  auth_value_methods :two_factor_modifications_require_password?
26
51
 
@@ -32,6 +57,62 @@ module Rodauth
32
57
  :two_factor_update_session
33
58
  )
34
59
 
60
+ route(:two_factor_manage, 'multifactor-manage') do |r|
61
+ require_account
62
+ before_two_factor_manage_route
63
+
64
+ r.get do
65
+ all_links = two_factor_setup_links + two_factor_remove_links
66
+ if all_links.length == 1
67
+ redirect all_links[0][1]
68
+ end
69
+ two_factor_manage_view
70
+ end
71
+ end
72
+
73
+ route(:two_factor_auth, 'multifactor-auth') do |r|
74
+ require_login
75
+ require_account_session
76
+ require_two_factor_setup
77
+ require_two_factor_not_authenticated
78
+ before_two_factor_auth_route
79
+
80
+ r.get do
81
+ if two_factor_auth_links.length == 1
82
+ redirect two_factor_auth_links[0][1]
83
+ end
84
+ two_factor_auth_view
85
+ end
86
+ end
87
+
88
+ route(:two_factor_disable, 'multifactor-disable') do |r|
89
+ require_account
90
+ require_two_factor_setup
91
+ before_two_factor_disable_route
92
+
93
+ r.get do
94
+ two_factor_disable_view
95
+ end
96
+
97
+ r.post do
98
+ if two_factor_password_match?(param(password_param))
99
+ transaction do
100
+ before_two_factor_disable
101
+ two_factor_remove
102
+ _two_factor_remove_all_from_session
103
+ after_two_factor_disable
104
+ end
105
+ set_notice_flash two_factor_disable_notice_flash
106
+ redirect two_factor_disable_redirect
107
+ end
108
+
109
+ set_response_error_status(invalid_password_error_status)
110
+ set_field_error(password_param, invalid_password_message)
111
+ set_error_flash two_factor_disable_error_flash
112
+ two_factor_disable_view
113
+ end
114
+ end
115
+
35
116
  def two_factor_modifications_require_password?
36
117
  modifications_require_password?
37
118
  end
@@ -44,7 +125,7 @@ module Rodauth
44
125
  return true if two_factor_authenticated?
45
126
 
46
127
  # True if authenticated via single factor and 2nd factor not setup
47
- !two_factor_authentication_setup?
128
+ !uses_two_factor_authentication?
48
129
  end
49
130
 
50
131
  def require_authentication
@@ -53,7 +134,7 @@ module Rodauth
53
134
  # Avoid database query if already authenticated via 2nd factor
54
135
  return if two_factor_authenticated?
55
136
 
56
- require_two_factor_authenticated if two_factor_authentication_setup?
137
+ require_two_factor_authenticated if uses_two_factor_authentication?
57
138
  end
58
139
 
59
140
  def require_two_factor_setup
@@ -67,8 +148,8 @@ module Rodauth
67
148
  redirect two_factor_need_setup_redirect
68
149
  end
69
150
 
70
- def require_two_factor_not_authenticated
71
- if two_factor_authenticated?
151
+ def require_two_factor_not_authenticated(auth_type = nil)
152
+ if two_factor_authenticated? || (auth_type && two_factor_login_type_match?(auth_type))
72
153
  set_redirect_error_status(two_factor_already_authenticated_error_status)
73
154
  set_redirect_error_flash two_factor_already_authenticated_error_flash
74
155
  redirect two_factor_already_authenticated_redirect
@@ -77,9 +158,12 @@ module Rodauth
77
158
 
78
159
  def require_two_factor_authenticated
79
160
  unless two_factor_authenticated?
161
+ if two_factor_auth_return_to_requested_location?
162
+ set_session_value(two_factor_auth_redirect_session_key, request.fullpath)
163
+ end
80
164
  set_redirect_error_status(two_factor_need_authentication_error_status)
81
165
  set_redirect_error_flash two_factor_need_authentication_error_flash
82
- redirect _two_factor_auth_required_redirect
166
+ redirect two_factor_auth_required_redirect
83
167
  end
84
168
  end
85
169
 
@@ -87,10 +171,6 @@ module Rodauth
87
171
  nil
88
172
  end
89
173
 
90
- def two_factor_auth_fallback_redirect
91
- nil
92
- end
93
-
94
174
  def two_factor_password_match?(password)
95
175
  if two_factor_modifications_require_password?
96
176
  password_match?(password)
@@ -100,25 +180,45 @@ module Rodauth
100
180
  end
101
181
 
102
182
  def two_factor_authenticated?
103
- !!session[two_factor_session_key]
183
+ authenticated_by && authenticated_by.length >= 2
104
184
  end
105
185
 
106
186
  def two_factor_authentication_setup?
107
- false
187
+ possible_authentication_methods.length >= 2
108
188
  end
109
189
 
110
190
  def uses_two_factor_authentication?
111
191
  return false unless logged_in?
112
- session[two_factor_setup_session_key] = two_factor_authentication_setup? unless session.has_key?(two_factor_setup_session_key)
192
+ set_session_value(two_factor_setup_session_key, two_factor_authentication_setup?) unless session.has_key?(two_factor_setup_session_key)
113
193
  session[two_factor_setup_session_key]
114
194
  end
115
195
 
196
+ def two_factor_login_type_match?(type)
197
+ authenticated_by && authenticated_by.include?(type)
198
+ end
199
+
116
200
  def two_factor_remove
117
201
  nil
118
202
  end
119
203
 
120
204
  private
121
205
 
206
+ def _two_factor_auth_links
207
+ (super if defined?(super)) || []
208
+ end
209
+
210
+ def _two_factor_setup_links
211
+ []
212
+ end
213
+
214
+ def _two_factor_remove_links
215
+ []
216
+ end
217
+
218
+ def _two_factor_remove_all_from_session
219
+ nil
220
+ end
221
+
122
222
  def after_close_account
123
223
  super if defined?(super)
124
224
  two_factor_remove
@@ -129,21 +229,25 @@ module Rodauth
129
229
  two_factor_remove_auth_failures
130
230
  after_two_factor_authentication
131
231
  set_notice_flash two_factor_auth_notice_flash
132
- redirect two_factor_auth_redirect
232
+ redirect_two_factor_authenticated
133
233
  end
134
234
 
135
- def two_factor_remove_session
136
- session.delete(two_factor_session_key)
137
- session[two_factor_setup_session_key] = false
235
+ def redirect_two_factor_authenticated
236
+ saved_two_factor_auth_redirect = remove_session_value(two_factor_auth_redirect_session_key)
237
+ redirect saved_two_factor_auth_redirect || two_factor_auth_redirect
138
238
  end
139
239
 
140
- def two_factor_update_session(type)
141
- session[two_factor_session_key] = type
142
- session[two_factor_setup_session_key] = true
240
+ def two_factor_remove_session(type)
241
+ authenticated_by.delete(type)
242
+ remove_session_value(two_factor_setup_session_key)
243
+ if authenticated_by.empty?
244
+ clear_session
245
+ end
143
246
  end
144
247
 
145
- def _two_factor_auth_required_redirect
146
- two_factor_auth_required_redirect || two_factor_auth_fallback_redirect || default_redirect
248
+ def two_factor_update_session(auth_type)
249
+ authenticated_by << auth_type
250
+ set_session_value(two_factor_setup_session_key, true)
147
251
  end
148
252
  end
149
253
  end
@@ -4,10 +4,6 @@ module Rodauth
4
4
  Feature.define(:verify_account, :VerifyAccount) do
5
5
  depends :login, :create_account, :email_base
6
6
 
7
- def_deprecated_alias :attempt_to_create_unverified_account_error_flash, :attempt_to_create_unverified_account_notice_message
8
- def_deprecated_alias :attempt_to_login_to_unverified_account_error_flash, :attempt_to_login_to_unverified_account_notice_message
9
- def_deprecated_alias :no_matching_verify_account_key_error_flash, :no_matching_verify_account_key_message
10
-
11
7
  error_flash "Unable to verify account"
12
8
  error_flash "Unable to resend verify account email", 'verify_account_resend'
13
9
  error_flash "An email has recently been sent to you with a link to verify your account", 'verify_account_email_recently_sent'
@@ -31,26 +27,29 @@ module Rodauth
31
27
  redirect(:verify_account_email_sent){default_post_email_redirect}
32
28
  redirect(:verify_account_email_recently_sent){default_post_email_redirect}
33
29
 
34
- auth_value_method :verify_account_email_subject, 'Verify Account'
30
+ translatable_method :verify_account_email_subject, 'Verify Account'
35
31
  auth_value_method :verify_account_key_param, 'key'
36
32
  auth_value_method :verify_account_autologin?, true
37
33
  auth_value_method :verify_account_table, :account_verification_keys
38
34
  auth_value_method :verify_account_id_column, :id
39
- auth_value_method :verify_account_email_last_sent_column, nil
35
+ auth_value_method :verify_account_email_last_sent_column, :email_last_sent
40
36
  auth_value_method :verify_account_skip_resend_email_within, 300
41
37
  auth_value_method :verify_account_key_column, :key
42
- auth_value_method :verify_account_resend_explanatory_text, "<p>If you no longer have the email to verify the account, you can request that it be resent to you:</p>"
38
+ translatable_method :verify_account_resend_explanatory_text, "<p>If you no longer have the email to verify the account, you can request that it be resent to you:</p>"
39
+ translatable_method :verify_account_resend_link_text, "Resend Verify Account Information"
43
40
  session_key :verify_account_session_key, :verify_account_key
44
- auth_value_method :verify_account_set_password?, false
41
+ auth_value_method :verify_account_set_password?, true
45
42
 
46
43
  auth_methods(
47
44
  :allow_resending_verify_account_email?,
48
45
  :create_verify_account_key,
49
46
  :create_verify_account_email,
50
47
  :get_verify_account_key,
48
+ :get_verify_account_email_last_sent,
51
49
  :remove_verify_account_key,
52
50
  :resend_verify_account_view,
53
51
  :send_verify_account_email,
52
+ :set_verify_account_email_last_sent,
54
53
  :verify_account,
55
54
  :verify_account_email_body,
56
55
  :verify_account_email_link,
@@ -71,6 +70,7 @@ module Rodauth
71
70
  end
72
71
 
73
72
  r.post do
73
+ verified = false
74
74
  if account_from_login(param(login_param)) && allow_resending_verify_account_email?
75
75
  if verify_account_email_recently_sent?
76
76
  set_redirect_error_flash verify_account_email_recently_sent_error_flash
@@ -80,8 +80,11 @@ module Rodauth
80
80
  before_verify_account_email_resend
81
81
  if verify_account_email_resend
82
82
  after_verify_account_email_resend
83
+ verified = true
83
84
  end
85
+ end
84
86
 
87
+ if verified
85
88
  set_notice_flash verify_account_email_sent_notice_flash
86
89
  else
87
90
  set_redirect_error_status(no_matching_login_error_status)
@@ -95,10 +98,11 @@ module Rodauth
95
98
  route do |r|
96
99
  verify_account_check_already_logged_in
97
100
  before_verify_account_route
101
+ @password_field_autocomplete_value = 'new-password'
98
102
 
99
103
  r.get do
100
104
  if key = param_or_nil(verify_account_key_param)
101
- session[verify_account_session_key] = key
105
+ set_session_value(verify_account_session_key, key)
102
106
  redirect(r.path)
103
107
  end
104
108
 
@@ -106,7 +110,7 @@ module Rodauth
106
110
  if account_from_verify_account_key(key)
107
111
  verify_account_view
108
112
  else
109
- session[verify_account_session_key] = nil
113
+ remove_session_value(verify_account_session_key)
110
114
  set_redirect_error_flash no_matching_verify_account_key_error_flash
111
115
  redirect require_login_redirect
112
116
  end
@@ -145,10 +149,10 @@ module Rodauth
145
149
  end
146
150
 
147
151
  if verify_account_autologin?
148
- update_session
152
+ autologin_session('verify_account')
149
153
  end
150
154
 
151
- session[verify_account_session_key] = nil
155
+ remove_session_value(verify_account_session_key)
152
156
  set_notice_flash verify_account_notice_flash
153
157
  redirect verify_account_redirect
154
158
  end
@@ -158,6 +162,10 @@ module Rodauth
158
162
  end
159
163
  end
160
164
 
165
+ def require_login_confirmation?
166
+ false
167
+ end
168
+
161
169
  def allow_resending_verify_account_email?
162
170
  account[account_status_column] == account_unverified_status_value
163
171
  end
@@ -201,7 +209,7 @@ module Rodauth
201
209
  end
202
210
 
203
211
  def send_verify_account_email
204
- create_verify_account_email.deliver!
212
+ send_email(create_verify_account_email)
205
213
  end
206
214
 
207
215
  def verify_account_email_link
@@ -220,14 +228,6 @@ module Rodauth
220
228
  false
221
229
  end
222
230
 
223
- def login_form_footer
224
- super + verify_account_resend_link
225
- end
226
-
227
- def verify_account_resend_link
228
- "<p><a href=\"#{prefix}/#{verify_account_resend_route}\">Resend Verify Account Information</a></p>"
229
- end
230
-
231
231
  def create_account_set_password?
232
232
  return false if verify_account_set_password?
233
233
  super
@@ -247,6 +247,14 @@ module Rodauth
247
247
 
248
248
  private
249
249
 
250
+ def _login_form_footer_links
251
+ links = super
252
+ if !param_or_nil(login_param) || ((account || account_from_login(param(login_param))) && allow_resending_verify_account_email?)
253
+ links << [30, verify_account_resend_path, verify_account_resend_link_text]
254
+ end
255
+ links
256
+ end
257
+
250
258
  def verify_account_email_recently_sent?
251
259
  (email_last_sent = get_verify_account_email_last_sent) && (Time.now - email_last_sent < verify_account_skip_resend_email_within)
252
260
  end
@@ -3,7 +3,7 @@
3
3
  module Rodauth
4
4
  Feature.define(:verify_account_grace_period, :VerifyAccountGracePeriod) do
5
5
  depends :verify_account
6
- error_flash "Cannot change login for unverified account. Please verify this account before changing the login.", "unverified_change_login"
6
+ error_flash "Please verify this account before changing the login", "unverified_change_login"
7
7
  redirect :unverified_change_login
8
8
 
9
9
  auth_value_method :verification_requested_at_column, :requested_at
@@ -23,7 +23,18 @@ module Rodauth
23
23
  end
24
24
 
25
25
  def open_account?
26
- super || account_in_unverified_grace_period?
26
+ super || (account_in_unverified_grace_period? && has_password?)
27
+ end
28
+
29
+ def verify_account_set_password?
30
+ false
31
+ end
32
+
33
+ def update_session
34
+ super
35
+ if account_in_unverified_grace_period?
36
+ set_session_value(unverified_account_session_key, true)
37
+ end
27
38
  end
28
39
 
29
40
  private
@@ -41,6 +52,10 @@ module Rodauth
41
52
  super if defined?(super)
42
53
  end
43
54
 
55
+ def allow_email_auth?
56
+ (defined?(super) ? super : true) && !account_in_unverified_grace_period?
57
+ end
58
+
44
59
  def verify_account_check_already_logged_in
45
60
  nil
46
61
  end
@@ -56,14 +71,8 @@ module Rodauth
56
71
  s
57
72
  end
58
73
 
59
- def update_session
60
- super
61
- if account_in_unverified_grace_period?
62
- session[unverified_account_session_key] = true
63
- end
64
- end
65
-
66
74
  def account_in_unverified_grace_period?
75
+ account || account_from_session
67
76
  account[account_status_column] == account_unverified_status_value &&
68
77
  verify_account_grace_period &&
69
78
  !verify_account_ds.where(Sequel.date_add(verification_requested_at_column, :seconds=>verify_account_grace_period) > Sequel::CURRENT_TIMESTAMP).empty?