rodauth 2.20.0 → 2.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +38 -442
- data/README.rdoc +15 -3
- data/doc/base.rdoc +1 -0
- data/doc/guides/internals.rdoc +11 -0
- data/doc/guides/paths.rdoc +3 -0
- data/doc/login_password_requirements_base.rdoc +1 -1
- data/doc/release_notes/2.21.0.txt +28 -0
- data/doc/release_notes/2.22.0.txt +43 -0
- data/doc/release_notes/2.23.0.txt +15 -0
- data/doc/reset_password.rdoc +16 -16
- data/doc/reset_password_notify.rdoc +17 -0
- data/lib/rodauth/features/active_sessions.rb +4 -2
- data/lib/rodauth/features/base.rb +25 -7
- data/lib/rodauth/features/change_password_notify.rb +2 -22
- data/lib/rodauth/features/email_auth.rb +1 -16
- data/lib/rodauth/features/http_basic_auth.rb +1 -1
- data/lib/rodauth/features/internal_request.rb +1 -1
- data/lib/rodauth/features/json.rb +2 -4
- data/lib/rodauth/features/jwt_cors.rb +1 -1
- data/lib/rodauth/features/lockout.rb +2 -18
- data/lib/rodauth/features/otp.rb +1 -1
- data/lib/rodauth/features/remember.rb +1 -1
- data/lib/rodauth/features/reset_password.rb +1 -16
- data/lib/rodauth/features/reset_password_notify.rb +16 -0
- data/lib/rodauth/features/sms_codes.rb +1 -1
- data/lib/rodauth/features/verify_account.rb +3 -20
- data/lib/rodauth/features/verify_account_grace_period.rb +13 -1
- data/lib/rodauth/version.rb +1 -1
- data/lib/rodauth.rb +27 -0
- data/templates/reset-password-notify-email.str +2 -0
- data/templates/webauthn-remove.str +1 -0
- metadata +13 -3
@@ -0,0 +1,15 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* The otp feature now uses the :use_path option when rendering QR
|
4
|
+
codes, resulting in significantly smaller svg images.
|
5
|
+
|
6
|
+
* Removing all multifactor authentication methods now removes the fact
|
7
|
+
that the session was authenticated via SMS, if the user used SMS as
|
8
|
+
an authentication method for the current session.
|
9
|
+
|
10
|
+
* The invalid domain check in the internal_request feature now works
|
11
|
+
correctly when using the rack master branch.
|
12
|
+
|
13
|
+
* The :httponly cookie option is no longer set automatically in the
|
14
|
+
remember feature if the :http_only cookie option was provided by the
|
15
|
+
user (rack recognizes both options).
|
data/doc/reset_password.rdoc
CHANGED
@@ -14,12 +14,12 @@ reset_password_autologin? :: Whether to autologin the user after successfully re
|
|
14
14
|
reset_password_button :: The text to use for the reset password button.
|
15
15
|
reset_password_deadline_column :: The column name in the +reset_password_table+ storing the deadline after which the token will be ignored.
|
16
16
|
reset_password_deadline_interval :: The amount of time for which to allow users to reset their passwords, 1 day by default. Only used if +set_deadline_values?+ is true.
|
17
|
-
reset_password_email_last_sent_column :: The email last sent column in the +reset_password_table+. Set to nil to always send a reset password email when requested.
|
18
|
-
reset_password_email_recently_sent_error_flash :: The flash error to show if not sending reset password email because one has been sent recently.
|
19
|
-
reset_password_email_recently_sent_redirect :: Where to redirect if not sending reset password email because one has been sent recently.
|
20
|
-
reset_password_email_sent_notice_flash :: The flash notice to show after a reset password email has been sent.
|
21
|
-
reset_password_email_sent_redirect :: Where to redirect after sending a reset password email.
|
22
|
-
reset_password_email_subject :: The subject to use for reset password
|
17
|
+
reset_password_email_last_sent_column :: The email last sent column in the +reset_password_table+. Set to nil to always send a reset password request email when requested.
|
18
|
+
reset_password_email_recently_sent_error_flash :: The flash error to show if not sending reset password request email because one has been sent recently.
|
19
|
+
reset_password_email_recently_sent_redirect :: Where to redirect if not sending reset password request email because one has been sent recently.
|
20
|
+
reset_password_email_sent_notice_flash :: The flash notice to show after a reset password request email has been sent.
|
21
|
+
reset_password_email_sent_redirect :: Where to redirect after sending a reset password request email.
|
22
|
+
reset_password_email_subject :: The subject to use for the reset password request email.
|
23
23
|
reset_password_error_flash :: The flash error to show after resetting a password.
|
24
24
|
reset_password_explanatory_text :: The text to display above the button to request a password reset.
|
25
25
|
reset_password_id_column :: The id column in the +reset_password_table+, should be a foreign key referencing the accounts table.
|
@@ -30,35 +30,35 @@ reset_password_page_title :: The page title to use on the reset password form.
|
|
30
30
|
reset_password_redirect :: Where to redirect after resetting a password.
|
31
31
|
reset_password_request_additional_form_tags :: HTML fragment containing additional form tags to use on the reset password request form.
|
32
32
|
reset_password_request_button :: The text to use for the reset password request button.
|
33
|
-
reset_password_request_error_flash :: The flash error to show if not able to send a reset password email.
|
33
|
+
reset_password_request_error_flash :: The flash error to show if not able to send a reset password request email.
|
34
34
|
reset_password_request_link_text :: The text to use for a link to the page to request a password reset.
|
35
35
|
reset_password_request_page_title :: The page title to use on the reset password request form.
|
36
36
|
reset_password_request_route :: The route to the reset password request action. Defaults to +reset-password-request+.
|
37
37
|
reset_password_route :: The route to the reset password action. Defaults to +reset-password+.
|
38
38
|
reset_password_session_key :: The key in the session to hold the reset password key temporarily.
|
39
|
-
reset_password_skip_resend_email_within :: The number of seconds before sending another reset password email, if +reset_password_email_last_sent_column+ is set.
|
39
|
+
reset_password_skip_resend_email_within :: The number of seconds before sending another reset password request email, if +reset_password_email_last_sent_column+ is set.
|
40
40
|
reset_password_table :: The name of the reset password keys table.
|
41
41
|
|
42
42
|
== Auth Methods
|
43
43
|
|
44
44
|
account_from_reset_password_key(key) :: Retrieve the account using the given reset password key, or return nil if no account matches.
|
45
45
|
after_reset_password :: Run arbitrary code after successfully resetting a password.
|
46
|
-
after_reset_password_request :: Run arbitrary code after sending the reset password email.
|
46
|
+
after_reset_password_request :: Run arbitrary code after sending the reset password request email.
|
47
47
|
before_reset_password :: Run arbitrary code before resetting a password.
|
48
|
-
before_reset_password_request :: Run arbitrary code before sending the reset password email.
|
48
|
+
before_reset_password_request :: Run arbitrary code before sending the reset password request email.
|
49
49
|
before_reset_password_request_route :: Run arbitrary code before handling a reset password request route.
|
50
50
|
before_reset_password_route :: Run arbitrary code before handling a reset password route.
|
51
|
-
create_reset_password_email :: A Mail::Message for the reset password email.
|
51
|
+
create_reset_password_email :: A Mail::Message for the reset password request email.
|
52
52
|
create_reset_password_key :: Add the reset password key data to the database.
|
53
|
-
get_reset_password_email_last_sent :: Get the last time a reset password email is sent, or nil if there is no last sent time.
|
53
|
+
get_reset_password_email_last_sent :: Get the last time a reset password request email is sent, or nil if there is no last sent time.
|
54
54
|
get_reset_password_key(id) :: Get the password reset key for the given account id from the database.
|
55
55
|
login_failed_reset_password_request_form :: The HTML to use for a form to request a password reset, shown on the login page after the user tries to login with an invalid password.
|
56
56
|
remove_reset_password_key :: Remove the reset password key for the current account, run after successful password reset.
|
57
|
-
reset_password_email_body :: The body to use for the reset password email.
|
58
|
-
reset_password_email_link :: The link to the reset password form in the reset password email.
|
57
|
+
reset_password_email_body :: The body to use for the reset password request email.
|
58
|
+
reset_password_email_link :: The link to the reset password form in the reset password request email.
|
59
59
|
reset_password_key_insert_hash :: The hash to insert into the +reset_password_table+.
|
60
60
|
reset_password_key_value :: The reset password key for the current account.
|
61
61
|
reset_password_request_view :: The HTML to use for the reset password request form.
|
62
62
|
reset_password_view :: The HTML to use for the reset password form.
|
63
|
-
send_reset_password_email :: Send the reset password email.
|
64
|
-
set_reset_password_email_last_sent :: Set the last time a reset password email is sent.
|
63
|
+
send_reset_password_email :: Send the reset password request email.
|
64
|
+
set_reset_password_email_last_sent :: Set the last time a reset password request email is sent.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
= Documentation for Reset Password Notify Feature
|
2
|
+
|
3
|
+
The reset password notify feature emails the user after the user has
|
4
|
+
reset their password. The user has already been sent a reset password
|
5
|
+
email by this point, so they know a password reset was requested, but
|
6
|
+
this feature allows for confirming that the password reset process
|
7
|
+
was completed. Depends on the reset_password feature.
|
8
|
+
|
9
|
+
== Auth Value Methods
|
10
|
+
|
11
|
+
reset_password_notify_email_subject :: The subject to use for the reset password notify email.
|
12
|
+
reset_password_notify_email_body :: The body to use for the reset password notify email.
|
13
|
+
|
14
|
+
== Auth Methods
|
15
|
+
|
16
|
+
create_reset_password_notify_email :: A Mail::Message for the reset password notify email.
|
17
|
+
send_reset_password_notify_email :: Send the reset password notify email.
|
@@ -13,7 +13,7 @@ module Rodauth
|
|
13
13
|
auth_value_method :active_sessions_last_use_column, :last_use
|
14
14
|
auth_value_method :active_sessions_session_id_column, :session_id
|
15
15
|
auth_value_method :active_sessions_table, :account_active_session_keys
|
16
|
-
translatable_method :global_logout_label, 'Logout all Logged In
|
16
|
+
translatable_method :global_logout_label, 'Logout all Logged In Sessions?'
|
17
17
|
auth_value_method :global_logout_param, 'global_logout'
|
18
18
|
auth_value_method :inactive_session_error_status, 401
|
19
19
|
auth_value_method :session_inactivity_deadline, 86400
|
@@ -81,7 +81,9 @@ module Rodauth
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def remove_current_session
|
84
|
-
|
84
|
+
if session_id = session[session_id_session_key]
|
85
|
+
active_sessions_ds.where(active_sessions_session_id_column=>compute_hmac(session_id)).delete
|
86
|
+
end
|
85
87
|
end
|
86
88
|
|
87
89
|
def remove_all_active_sessions
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
|
+
require 'rack/request'
|
4
|
+
require 'rack/utils'
|
5
|
+
|
3
6
|
module Rodauth
|
4
7
|
Feature.define(:base, :Base) do
|
5
8
|
after 'login'
|
@@ -91,6 +94,7 @@ module Rodauth
|
|
91
94
|
:inputmode_for_field?,
|
92
95
|
:logged_in?,
|
93
96
|
:login_required,
|
97
|
+
:null_byte_parameter_value,
|
94
98
|
:open_account?,
|
95
99
|
:password_match?,
|
96
100
|
:random_key,
|
@@ -338,6 +342,11 @@ module Rodauth
|
|
338
342
|
require_login
|
339
343
|
end
|
340
344
|
|
345
|
+
def require_account
|
346
|
+
require_authentication
|
347
|
+
require_account_session
|
348
|
+
end
|
349
|
+
|
341
350
|
def account_initial_status_value
|
342
351
|
account_open_status_value
|
343
352
|
end
|
@@ -441,7 +450,16 @@ module Rodauth
|
|
441
450
|
# parameter with that name.
|
442
451
|
def param_or_nil(key)
|
443
452
|
value = raw_param(key)
|
444
|
-
|
453
|
+
unless value.nil?
|
454
|
+
value = value.to_s
|
455
|
+
value = null_byte_parameter_value(key, value) if value.include?("\0")
|
456
|
+
end
|
457
|
+
value
|
458
|
+
end
|
459
|
+
|
460
|
+
# Return nil by default for values with null bytes
|
461
|
+
def null_byte_parameter_value(key, value)
|
462
|
+
nil
|
445
463
|
end
|
446
464
|
|
447
465
|
def raw_param(key)
|
@@ -496,6 +514,11 @@ module Rodauth
|
|
496
514
|
request.redirect(path)
|
497
515
|
end
|
498
516
|
|
517
|
+
def return_response(body=nil)
|
518
|
+
response.write(body) if body
|
519
|
+
request.halt
|
520
|
+
end
|
521
|
+
|
499
522
|
def route_path(route, opts={})
|
500
523
|
path = "#{prefix}/#{route}"
|
501
524
|
path += "?#{Rack::Utils.build_nested_query(opts)}" unless opts.empty?
|
@@ -524,11 +547,6 @@ module Rodauth
|
|
524
547
|
Rack::Utils.secure_compare(provided.ljust(actual.length), actual) && provided.length == actual.length
|
525
548
|
end
|
526
549
|
|
527
|
-
def require_account
|
528
|
-
require_authentication
|
529
|
-
require_account_session
|
530
|
-
end
|
531
|
-
|
532
550
|
def require_account_session
|
533
551
|
unless account_from_session
|
534
552
|
clear_session
|
@@ -756,7 +774,7 @@ module Rodauth
|
|
756
774
|
num = ds.update(values)
|
757
775
|
if num == 1
|
758
776
|
values.each do |k, v|
|
759
|
-
|
777
|
+
hash[k] = Sequel::CURRENT_TIMESTAMP == v ? Time.now : v
|
760
778
|
end
|
761
779
|
end
|
762
780
|
num
|
@@ -3,31 +3,11 @@
|
|
3
3
|
module Rodauth
|
4
4
|
Feature.define(:change_password_notify, :ChangePasswordNotify) do
|
5
5
|
depends :change_password, :email_base
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
auth_value_methods(
|
10
|
-
:password_changed_email_body
|
11
|
-
)
|
12
|
-
auth_methods(
|
13
|
-
:create_password_changed_email,
|
14
|
-
:send_password_changed_email
|
15
|
-
)
|
6
|
+
loaded_templates %w'password-changed-email'
|
7
|
+
email :password_changed, 'Password Changed', :translatable=>true
|
16
8
|
|
17
9
|
private
|
18
10
|
|
19
|
-
def send_password_changed_email
|
20
|
-
send_email(create_password_changed_email)
|
21
|
-
end
|
22
|
-
|
23
|
-
def create_password_changed_email
|
24
|
-
create_email(password_changed_email_subject, password_changed_email_body)
|
25
|
-
end
|
26
|
-
|
27
|
-
def password_changed_email_body
|
28
|
-
render('password-changed-email')
|
29
|
-
end
|
30
|
-
|
31
11
|
def after_change_password
|
32
12
|
super
|
33
13
|
send_password_changed_email
|
@@ -19,10 +19,10 @@ module Rodauth
|
|
19
19
|
button 'Send Login Link Via Email', 'email_auth_request'
|
20
20
|
redirect(:email_auth_email_sent){default_post_email_redirect}
|
21
21
|
redirect(:email_auth_email_recently_sent){default_post_email_redirect}
|
22
|
+
email :email_auth, 'Login Link'
|
22
23
|
|
23
24
|
auth_value_method :email_auth_deadline_column, :deadline
|
24
25
|
auth_value_method :email_auth_deadline_interval, {:days=>1}.freeze
|
25
|
-
translatable_method :email_auth_email_subject, 'Login Link'
|
26
26
|
auth_value_method :email_auth_id_column, :id
|
27
27
|
auth_value_method :email_auth_key_column, :key
|
28
28
|
auth_value_method :email_auth_key_param, 'key'
|
@@ -33,9 +33,7 @@ module Rodauth
|
|
33
33
|
session_key :email_auth_session_key, :email_auth_key
|
34
34
|
|
35
35
|
auth_methods(
|
36
|
-
:create_email_auth_email,
|
37
36
|
:create_email_auth_key,
|
38
|
-
:email_auth_email_body,
|
39
37
|
:email_auth_email_link,
|
40
38
|
:email_auth_key_insert_hash,
|
41
39
|
:email_auth_key_value,
|
@@ -43,7 +41,6 @@ module Rodauth
|
|
43
41
|
:get_email_auth_key,
|
44
42
|
:get_email_auth_email_last_sent,
|
45
43
|
:remove_email_auth_key,
|
46
|
-
:send_email_auth_email,
|
47
44
|
:set_email_auth_email_last_sent
|
48
45
|
)
|
49
46
|
|
@@ -137,10 +134,6 @@ module Rodauth
|
|
137
134
|
@account = _account_from_email_auth_key(key)
|
138
135
|
end
|
139
136
|
|
140
|
-
def send_email_auth_email
|
141
|
-
send_email(create_email_auth_email)
|
142
|
-
end
|
143
|
-
|
144
137
|
def email_auth_email_link
|
145
138
|
token_link(email_auth_route, email_auth_key_param, email_auth_key_value)
|
146
139
|
end
|
@@ -233,14 +226,6 @@ module Rodauth
|
|
233
226
|
@email_auth_key_value = random_key
|
234
227
|
end
|
235
228
|
|
236
|
-
def create_email_auth_email
|
237
|
-
create_email(email_auth_email_subject, email_auth_email_body)
|
238
|
-
end
|
239
|
-
|
240
|
-
def email_auth_email_body
|
241
|
-
render('email-auth-email')
|
242
|
-
end
|
243
|
-
|
244
229
|
def use_date_arithmetic?
|
245
230
|
super || db.database_type == :mysql
|
246
231
|
end
|
@@ -156,8 +156,7 @@ module Rodauth
|
|
156
156
|
end
|
157
157
|
elsif only_json?
|
158
158
|
response.status = json_response_error_status
|
159
|
-
|
160
|
-
request.halt
|
159
|
+
return_response non_json_request_error_message
|
161
160
|
end
|
162
161
|
|
163
162
|
super
|
@@ -175,8 +174,7 @@ module Rodauth
|
|
175
174
|
def _return_json_response
|
176
175
|
response.status ||= json_response_error_status if json_response[json_response_error_key]
|
177
176
|
response['Content-Type'] ||= json_response_content_type
|
178
|
-
|
179
|
-
request.halt
|
177
|
+
return_response _json_response_body(json_response)
|
180
178
|
end
|
181
179
|
|
182
180
|
def include_success_messages?
|
@@ -41,7 +41,7 @@ module Rodauth
|
|
41
41
|
response['Access-Control-Allow-Headers'] = jwt_cors_allow_headers
|
42
42
|
response['Access-Control-Max-Age'] = jwt_cors_max_age.to_s
|
43
43
|
response.status = 204
|
44
|
-
|
44
|
+
return_response
|
45
45
|
end
|
46
46
|
|
47
47
|
response['Access-Control-Expose-Headers'] = jwt_cors_expose_headers
|
@@ -25,6 +25,7 @@ module Rodauth
|
|
25
25
|
redirect :unlock_account
|
26
26
|
redirect(:unlock_account_request){default_post_email_redirect}
|
27
27
|
redirect(:unlock_account_email_recently_sent){default_post_email_redirect}
|
28
|
+
email :unlock_account, 'Unlock Account'
|
28
29
|
|
29
30
|
auth_value_method :unlock_account_autologin?, true
|
30
31
|
auth_value_method :max_invalid_logins, 100
|
@@ -37,7 +38,6 @@ module Rodauth
|
|
37
38
|
auth_value_method :account_lockouts_email_last_sent_column, :email_last_sent
|
38
39
|
auth_value_method :account_lockouts_deadline_column, :deadline
|
39
40
|
auth_value_method :account_lockouts_deadline_interval, {:days=>1}.freeze
|
40
|
-
translatable_method :unlock_account_email_subject, 'Unlock Account'
|
41
41
|
translatable_method :unlock_account_explanatory_text, '<p>This account is currently locked out. You can unlock the account:</p>'
|
42
42
|
translatable_method :unlock_account_request_explanatory_text, '<p>This account is currently locked out. You can request that the account be unlocked:</p>'
|
43
43
|
auth_value_method :unlock_account_key_param, 'key'
|
@@ -47,15 +47,12 @@ module Rodauth
|
|
47
47
|
|
48
48
|
auth_methods(
|
49
49
|
:clear_invalid_login_attempts,
|
50
|
-
:create_unlock_account_email,
|
51
50
|
:generate_unlock_account_key,
|
52
51
|
:get_unlock_account_key,
|
53
52
|
:get_unlock_account_email_last_sent,
|
54
53
|
:invalid_login_attempted,
|
55
54
|
:locked_out?,
|
56
|
-
:send_unlock_account_email,
|
57
55
|
:set_unlock_account_email_last_sent,
|
58
|
-
:unlock_account_email_body,
|
59
56
|
:unlock_account_email_link,
|
60
57
|
:unlock_account,
|
61
58
|
:unlock_account_key
|
@@ -226,10 +223,6 @@ module Rodauth
|
|
226
223
|
@account = _account_from_unlock_key(key)
|
227
224
|
end
|
228
225
|
|
229
|
-
def send_unlock_account_email
|
230
|
-
send_email(create_unlock_account_email)
|
231
|
-
end
|
232
|
-
|
233
226
|
def unlock_account_email_link
|
234
227
|
token_link(unlock_account_route, unlock_account_key_param, unlock_account_key_value)
|
235
228
|
end
|
@@ -284,16 +277,7 @@ module Rodauth
|
|
284
277
|
def show_lockout_page
|
285
278
|
set_response_error_reason_status(:account_locked_out, lockout_error_status)
|
286
279
|
set_error_flash login_lockout_error_flash
|
287
|
-
|
288
|
-
request.halt
|
289
|
-
end
|
290
|
-
|
291
|
-
def create_unlock_account_email
|
292
|
-
create_email(unlock_account_email_subject, unlock_account_email_body)
|
293
|
-
end
|
294
|
-
|
295
|
-
def unlock_account_email_body
|
296
|
-
render('unlock-account-email')
|
280
|
+
return_response unlock_account_request_view
|
297
281
|
end
|
298
282
|
|
299
283
|
def unlock_account_email_recently_sent?
|
data/lib/rodauth/features/otp.rb
CHANGED
@@ -303,7 +303,7 @@ module Rodauth
|
|
303
303
|
end
|
304
304
|
|
305
305
|
def otp_qr_code
|
306
|
-
RQRCode::QRCode.new(otp_provisioning_uri).as_svg(:module_size=>8, :viewbox=>true)
|
306
|
+
RQRCode::QRCode.new(otp_provisioning_uri).as_svg(:module_size=>8, :viewbox=>true, :use_path=>true)
|
307
307
|
end
|
308
308
|
|
309
309
|
def otp_user_key
|
@@ -144,7 +144,7 @@ module Rodauth
|
|
144
144
|
opts[:value] = "#{account_id}_#{convert_token_key(remember_key_value)}"
|
145
145
|
opts[:expires] = convert_timestamp(active_remember_key_ds.get(remember_deadline_column))
|
146
146
|
opts[:path] = "/" unless opts.key?(:path)
|
147
|
-
opts[:httponly] = true unless opts.key?(:httponly)
|
147
|
+
opts[:httponly] = true unless opts.key?(:httponly) || opts.key?(:http_only)
|
148
148
|
opts[:secure] = true unless opts.key?(:secure) || !request.ssl?
|
149
149
|
::Rack::Utils.set_cookie_header!(response.headers, remember_cookie_key, opts)
|
150
150
|
end
|
@@ -24,10 +24,10 @@ module Rodauth
|
|
24
24
|
redirect
|
25
25
|
redirect(:reset_password_email_sent){default_post_email_redirect}
|
26
26
|
redirect(:reset_password_email_recently_sent){default_post_email_redirect}
|
27
|
+
email :reset_password, 'Reset Password'
|
27
28
|
|
28
29
|
auth_value_method :reset_password_deadline_column, :deadline
|
29
30
|
auth_value_method :reset_password_deadline_interval, {:days=>1}.freeze
|
30
|
-
translatable_method :reset_password_email_subject, 'Reset Password'
|
31
31
|
auth_value_method :reset_password_key_param, 'key'
|
32
32
|
auth_value_method :reset_password_autologin?, false
|
33
33
|
auth_value_method :reset_password_table, :account_password_reset_keys
|
@@ -41,16 +41,13 @@ module Rodauth
|
|
41
41
|
|
42
42
|
auth_methods(
|
43
43
|
:create_reset_password_key,
|
44
|
-
:create_reset_password_email,
|
45
44
|
:get_reset_password_key,
|
46
45
|
:get_reset_password_email_last_sent,
|
47
46
|
:login_failed_reset_password_request_form,
|
48
47
|
:remove_reset_password_key,
|
49
|
-
:reset_password_email_body,
|
50
48
|
:reset_password_email_link,
|
51
49
|
:reset_password_key_insert_hash,
|
52
50
|
:reset_password_key_value,
|
53
|
-
:send_reset_password_email,
|
54
51
|
:set_reset_password_email_last_sent
|
55
52
|
)
|
56
53
|
auth_private_methods(
|
@@ -187,10 +184,6 @@ module Rodauth
|
|
187
184
|
@account = _account_from_reset_password_key(key)
|
188
185
|
end
|
189
186
|
|
190
|
-
def send_reset_password_email
|
191
|
-
send_email(create_reset_password_email)
|
192
|
-
end
|
193
|
-
|
194
187
|
def reset_password_email_link
|
195
188
|
token_link(reset_password_route, reset_password_key_param, reset_password_key_value)
|
196
189
|
end
|
@@ -241,18 +234,10 @@ module Rodauth
|
|
241
234
|
@reset_password_key_value = random_key
|
242
235
|
end
|
243
236
|
|
244
|
-
def create_reset_password_email
|
245
|
-
create_email(reset_password_email_subject, reset_password_email_body)
|
246
|
-
end
|
247
|
-
|
248
237
|
def login_failed_reset_password_request_form
|
249
238
|
render("reset-password-request")
|
250
239
|
end
|
251
240
|
|
252
|
-
def reset_password_email_body
|
253
|
-
render('reset-password-email')
|
254
|
-
end
|
255
|
-
|
256
241
|
def use_date_arithmetic?
|
257
242
|
super || db.database_type == :mysql
|
258
243
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Rodauth
|
4
|
+
Feature.define(:reset_password_notify, :ResetPasswordNotify) do
|
5
|
+
depends :reset_password
|
6
|
+
loaded_templates %w'reset-password-notify-email'
|
7
|
+
email :reset_password_notify, 'Password Reset Completed', :translatable=>true
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def after_reset_password
|
12
|
+
super
|
13
|
+
send_reset_password_notify_email
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -26,8 +26,8 @@ module Rodauth
|
|
26
26
|
redirect
|
27
27
|
redirect(:verify_account_email_sent){default_post_email_redirect}
|
28
28
|
redirect(:verify_account_email_recently_sent){default_post_email_redirect}
|
29
|
+
email :verify_account, 'Verify Account'
|
29
30
|
|
30
|
-
translatable_method :verify_account_email_subject, 'Verify Account'
|
31
31
|
auth_value_method :verify_account_key_param, 'key'
|
32
32
|
auth_value_method :verify_account_autologin?, true
|
33
33
|
auth_value_method :verify_account_table, :account_verification_keys
|
@@ -43,14 +43,11 @@ module Rodauth
|
|
43
43
|
auth_methods(
|
44
44
|
:allow_resending_verify_account_email?,
|
45
45
|
:create_verify_account_key,
|
46
|
-
:create_verify_account_email,
|
47
46
|
:get_verify_account_key,
|
48
47
|
:get_verify_account_email_last_sent,
|
49
48
|
:remove_verify_account_key,
|
50
|
-
:send_verify_account_email,
|
51
49
|
:set_verify_account_email_last_sent,
|
52
50
|
:verify_account,
|
53
|
-
:verify_account_email_body,
|
54
51
|
:verify_account_email_link,
|
55
52
|
:verify_account_key_insert_hash,
|
56
53
|
:verify_account_key_value
|
@@ -198,8 +195,7 @@ module Rodauth
|
|
198
195
|
if account_from_login(login) && allow_resending_verify_account_email?
|
199
196
|
set_response_error_reason_status(:already_an_unverified_account_with_this_login, unopen_account_error_status)
|
200
197
|
set_error_flash attempt_to_create_unverified_account_error_flash
|
201
|
-
|
202
|
-
request.halt
|
198
|
+
return_response resend_verify_account_view
|
203
199
|
end
|
204
200
|
super
|
205
201
|
end
|
@@ -212,10 +208,6 @@ module Rodauth
|
|
212
208
|
account_unverified_status_value
|
213
209
|
end
|
214
210
|
|
215
|
-
def send_verify_account_email
|
216
|
-
send_email(create_verify_account_email)
|
217
|
-
end
|
218
|
-
|
219
211
|
def verify_account_email_link
|
220
212
|
token_link(verify_account_route, verify_account_key_param, verify_account_key_value)
|
221
213
|
end
|
@@ -275,8 +267,7 @@ module Rodauth
|
|
275
267
|
unless open_account?
|
276
268
|
set_response_error_reason_status(:unverified_account, unopen_account_error_status)
|
277
269
|
set_error_flash attempt_to_login_to_unverified_account_error_flash
|
278
|
-
|
279
|
-
request.halt
|
270
|
+
return_response resend_verify_account_view
|
280
271
|
end
|
281
272
|
super
|
282
273
|
end
|
@@ -311,14 +302,6 @@ module Rodauth
|
|
311
302
|
{verify_account_id_column=>account_id, verify_account_key_column=>verify_account_key_value}
|
312
303
|
end
|
313
304
|
|
314
|
-
def create_verify_account_email
|
315
|
-
create_email(verify_account_email_subject, verify_account_email_body)
|
316
|
-
end
|
317
|
-
|
318
|
-
def verify_account_email_body
|
319
|
-
render('verify-account-email')
|
320
|
-
end
|
321
|
-
|
322
305
|
def verify_account_ds(id=account_id)
|
323
306
|
db[verify_account_table].where(verify_account_id_column=>id)
|
324
307
|
end
|
@@ -30,10 +30,17 @@ module Rodauth
|
|
30
30
|
false
|
31
31
|
end
|
32
32
|
|
33
|
+
def require_login
|
34
|
+
if unverified_grace_period_expired?
|
35
|
+
clear_session
|
36
|
+
end
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
33
40
|
def update_session
|
34
41
|
super
|
35
42
|
if account_in_unverified_grace_period?
|
36
|
-
set_session_value(unverified_account_session_key,
|
43
|
+
set_session_value(unverified_account_session_key, Time.now.to_i + verify_account_grace_period)
|
37
44
|
end
|
38
45
|
end
|
39
46
|
|
@@ -78,6 +85,11 @@ module Rodauth
|
|
78
85
|
!verify_account_ds.where(Sequel.date_add(verification_requested_at_column, :seconds=>verify_account_grace_period) > Sequel::CURRENT_TIMESTAMP).empty?
|
79
86
|
end
|
80
87
|
|
88
|
+
def unverified_grace_period_expired?
|
89
|
+
return false unless expires_at = session[unverified_account_session_key]
|
90
|
+
expires_at.is_a?(Integer) && Time.now.to_i > expires_at
|
91
|
+
end
|
92
|
+
|
81
93
|
def use_date_arithmetic?
|
82
94
|
true
|
83
95
|
end
|
data/lib/rodauth/version.rb
CHANGED
data/lib/rodauth.rb
CHANGED
@@ -233,6 +233,33 @@ module Rodauth
|
|
233
233
|
end
|
234
234
|
end
|
235
235
|
|
236
|
+
def email(type, subject, opts = {})
|
237
|
+
subject_method = :"#{type}_email_subject"
|
238
|
+
body_method = :"#{type}_email_body"
|
239
|
+
create_method = :"create_#{type}_email"
|
240
|
+
send_method = :"send_#{type}_email"
|
241
|
+
|
242
|
+
translatable_method subject_method, subject
|
243
|
+
auth_methods create_method, send_method
|
244
|
+
|
245
|
+
body_template = "#{type.to_s.tr('_', '-')}-email"
|
246
|
+
if opts[:translatable]
|
247
|
+
auth_value_methods body_method
|
248
|
+
define_method(body_method){translate(body_method, render(body_template))}
|
249
|
+
else
|
250
|
+
auth_methods body_method
|
251
|
+
define_method(body_method){render(body_template)}
|
252
|
+
end
|
253
|
+
|
254
|
+
define_method(create_method) do
|
255
|
+
create_email(send(subject_method), send(body_method))
|
256
|
+
end
|
257
|
+
|
258
|
+
define_method(send_method) do
|
259
|
+
send_email(send(create_method))
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
236
263
|
def additional_form_tags(name=feature_name)
|
237
264
|
auth_value_method(:"#{name}_additional_form_tags", nil)
|
238
265
|
end
|
@@ -4,6 +4,7 @@
|
|
4
4
|
#{rodauth.render('password-field') if rodauth.two_factor_modifications_require_password?}
|
5
5
|
<fieldset class="form-group mb-3">
|
6
6
|
#{(usage = rodauth.account_webauthn_usage; last_id = usage.keys.last; usage;).map do |id, last_use|
|
7
|
+
last_use = last_use.strftime("%F %T") if last_use.is_a?(Time)
|
7
8
|
input = rodauth.input_field_string(rodauth.webauthn_remove_param, "webauthn-remove-#{h id}", :type=>'radio', :class=>"form-check-input", :skip_error_message=>true, :value=>id, :required=>false)
|
8
9
|
label = "<label class=\"rodauth-webauthn-id form-check-label\" for=\"webauthn-remove-#{h id}\">Last Use: #{last_use}</label>"
|
9
10
|
error = rodauth.formatted_field_error(rodauth.webauthn_remove_param) if id == last_id
|