rodauth 1.18.0 → 1.19.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 +24 -0
- data/README.rdoc +20 -11
- data/doc/base.rdoc +2 -2
- data/doc/email_auth.rdoc +53 -0
- data/doc/email_base.rdoc +4 -0
- data/doc/internals.rdoc +3 -3
- data/doc/lockout.rdoc +28 -48
- data/doc/login.rdoc +4 -4
- data/doc/otp.rdoc +1 -3
- data/doc/release_notes/1.19.0.txt +116 -0
- data/doc/reset_password.rdoc +29 -49
- data/doc/verify_account.rdoc +30 -50
- data/doc/verify_login_change.rdoc +4 -0
- data/lib/rodauth/features/base.rb +0 -1
- data/lib/rodauth/features/change_login.rb +4 -0
- data/lib/rodauth/features/disallow_common_passwords.rb +1 -1
- data/lib/rodauth/features/email_auth.rb +253 -0
- data/lib/rodauth/features/email_base.rb +2 -0
- data/lib/rodauth/features/lockout.rb +35 -6
- data/lib/rodauth/features/login.rb +46 -9
- data/lib/rodauth/features/otp.rb +8 -4
- data/lib/rodauth/features/recovery_codes.rb +0 -2
- data/lib/rodauth/features/remember.rb +1 -1
- data/lib/rodauth/features/reset_password.rb +32 -4
- data/lib/rodauth/features/sms_codes.rb +2 -8
- data/lib/rodauth/features/two_factor_base.rb +22 -15
- data/lib/rodauth/features/verify_account.rb +27 -1
- data/lib/rodauth/features/verify_login_change.rb +30 -7
- data/lib/rodauth/migrations.rb +2 -8
- data/lib/rodauth/version.rb +1 -1
- data/spec/email_auth_spec.rb +285 -0
- data/spec/lockout_spec.rb +24 -2
- data/spec/login_spec.rb +47 -1
- data/spec/migrate/001_tables.rb +13 -0
- data/spec/migrate_travis/001_tables.rb +10 -0
- data/spec/reset_password_spec.rb +20 -2
- data/spec/two_factor_spec.rb +46 -0
- data/spec/verify_account_grace_period_spec.rb +1 -1
- data/spec/verify_account_spec.rb +33 -3
- data/spec/verify_login_change_spec.rb +54 -1
- data/templates/email-auth-email.str +5 -0
- data/templates/email-auth-request-form.str +7 -0
- data/templates/email-auth.str +5 -0
- data/templates/login-display.str +4 -0
- data/templates/login.str +2 -2
- data/templates/otp-setup.str +13 -11
- metadata +12 -2
data/doc/reset_password.rdoc
CHANGED
@@ -8,73 +8,53 @@ the login feature.
|
|
8
8
|
|
9
9
|
== Auth Value Methods
|
10
10
|
|
11
|
-
no_matching_reset_password_key_message :: The flash error message to show if attempting
|
12
|
-
|
13
|
-
|
14
|
-
reset_password_additional_form_tags :: HTML fragment containing additional form
|
15
|
-
tags to use on the reset password form.
|
16
|
-
reset_password_autologin? :: Whether to autologin the user after successfully
|
17
|
-
resetting a password.
|
11
|
+
no_matching_reset_password_key_message :: The flash error message to show if attempting to access the reset password form with an invalid key.
|
12
|
+
reset_password_additional_form_tags :: HTML fragment containing additional form tags to use on the reset password form.
|
13
|
+
reset_password_autologin? :: Whether to autologin the user after successfully resetting a password.
|
18
14
|
reset_password_button :: The text to use for the reset password button.
|
19
|
-
reset_password_deadline_column :: The column name in the reset password keys table storing
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
password email has been sent.
|
26
|
-
reset_password_email_sent_redirect :: Where to redirect after sending a reset
|
27
|
-
password email.
|
15
|
+
reset_password_deadline_column :: The column name in the reset password keys table storing the deadline after which the token will be ignored.
|
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_recently_sent_error_flash :: The flash error to show if not sending reset password email because one has been sent recently.
|
18
|
+
reset_password_email_recently_sent_redirect :: Where to redirect if not sending reset password email because one has been sent recently.
|
19
|
+
reset_password_email_sent_notice_flash :: The flash notice to show after a reset password email has been sent.
|
20
|
+
reset_password_email_sent_redirect :: Where to redirect after sending a reset password email.
|
28
21
|
reset_password_email_subject :: The subject to use for reset password emails.
|
29
22
|
reset_password_error_flash :: The flash error to show after resetting a password.
|
30
|
-
|
31
|
-
|
32
|
-
reset_password_key_column :: The reset password key/token column in the reset
|
33
|
-
password keys table.
|
23
|
+
reset_password_email_last_sent_column :: The email last sent column in the reset password keys table. nil by default, so a reset password email is always sent when requested by default.
|
24
|
+
reset_password_id_column :: The id column in the reset password keys table, should be a foreign key referencing the accounts table.
|
25
|
+
reset_password_key_column :: The reset password key/token column in the reset password keys table.
|
34
26
|
reset_password_key_param :: The parameter name to use for the reset password key.
|
35
27
|
reset_password_redirect :: Where to redirect after resetting a password.
|
36
|
-
reset_password_request_additional_form_tags :: HTML fragment containing additional form
|
37
|
-
tags to use on the reset password request
|
38
|
-
form.
|
28
|
+
reset_password_request_additional_form_tags :: HTML fragment containing additional form tags to use on the reset password request form.
|
39
29
|
reset_password_request_button :: The text to use for the reset password request button.
|
40
|
-
reset_password_request_error_flash :: The flash error to show if not able to send a reset
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
reset_password_request_route :: The route to the reset password request action.
|
45
|
-
Defaults to +reset-password-request+.
|
46
|
-
reset_password_route :: The route to the reset password action. Defaults to
|
47
|
-
+reset-password+.
|
30
|
+
reset_password_request_error_flash :: The flash error to show if not able to send a reset password email.
|
31
|
+
reset_password_request_link :: The HTML to use for a link to the page to request a password reset.
|
32
|
+
reset_password_request_route :: The route to the reset password request action. Defaults to +reset-password-request+.
|
33
|
+
reset_password_route :: The route to the reset password action. Defaults to +reset-password+.
|
48
34
|
reset_password_session_key :: The key in the session to hold the reset password key temporarily.
|
35
|
+
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.
|
49
36
|
reset_password_table :: The name of the reset password keys table.
|
50
37
|
|
51
38
|
== Auth Methods
|
52
39
|
|
53
|
-
account_from_reset_password_key(key) :: Retrieve the account using the given reset
|
54
|
-
password key, or return nil if no account
|
55
|
-
matches.
|
40
|
+
account_from_reset_password_key(key) :: Retrieve the account using the given reset password key, or return nil if no account matches.
|
56
41
|
after_reset_password :: Run arbitrary code after successfully resetting a password.
|
57
|
-
after_reset_password_request :: Run arbitrary code after sending the reset password
|
58
|
-
email.
|
42
|
+
after_reset_password_request :: Run arbitrary code after sending the reset password email.
|
59
43
|
before_reset_password :: Run arbitrary code before resetting a password.
|
60
|
-
before_reset_password_request :: Run arbitrary code before sending the reset password
|
61
|
-
|
44
|
+
before_reset_password_request :: Run arbitrary code before sending the reset password email.
|
45
|
+
before_reset_password_request_route :: Run arbitrary code before handling a reset password request route.
|
62
46
|
before_reset_password_route :: Run arbitrary code before handling a reset password route.
|
63
47
|
create_reset_password_key :: Add the reset password key data to the database.
|
64
48
|
create_reset_password_email :: A Mail::Message for the reset password email.
|
65
|
-
|
66
|
-
|
67
|
-
login_failed_reset_password_request_form :: The HTML to use for a form to request a password
|
68
|
-
|
69
|
-
tries to login with an invalid password.
|
70
|
-
remove_reset_password_key :: Remove the reset password key for the current account,
|
71
|
-
run after successful password reset.
|
49
|
+
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.
|
50
|
+
get_reset_password_key(id) :: Get the password reset key for the given account id from the database.
|
51
|
+
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.
|
52
|
+
remove_reset_password_key :: Remove the reset password key for the current account, run after successful password reset.
|
72
53
|
reset_password_email_body :: The body to use for the reset password email.
|
73
|
-
reset_password_email_link :: The link to the reset password form in the reset
|
74
|
-
|
75
|
-
reset_password_key_insert_hash :: The hash to insert into the reset password keys
|
76
|
-
table.
|
54
|
+
reset_password_email_link :: The link to the reset password form in the reset password email.
|
55
|
+
reset_password_key_insert_hash :: The hash to insert into the reset password keys table.
|
77
56
|
reset_password_key_value :: The reset password key for the current account.
|
78
57
|
reset_password_request_view :: The HTML to use for the reset password request form.
|
79
58
|
reset_password_view :: The HTML to use for the reset password form.
|
80
59
|
send_reset_password_email :: Send the reset password email.
|
60
|
+
set_reset_password_email_last_sent :: Set the last time a reset password email is sent.
|
data/doc/verify_account.rdoc
CHANGED
@@ -7,76 +7,56 @@ after verifying the account. Depends on the login and create account features.
|
|
7
7
|
|
8
8
|
== Auth Value Methods
|
9
9
|
|
10
|
-
attempt_to_create_unverified_account_notice_message :: Message displayed when attempting to
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
an invalid verify account key is used.
|
16
|
-
verify_account_additional_form_tags :: HTML fragment containing additional form
|
17
|
-
tags to use on the verify account form.
|
18
|
-
verify_account_autologin? :: Whether to autologin the user after successful
|
19
|
-
account verification, true by default.
|
10
|
+
attempt_to_create_unverified_account_notice_message :: Message displayed when attempting to create an account awaiting verification.
|
11
|
+
attempt_to_login_to_unverified_account_notice_message :: Message displayed when attempting to login to an account awaiting verification.
|
12
|
+
no_matching_verify_account_key_message :: The flash error message to show when an invalid verify account key is used.
|
13
|
+
verify_account_additional_form_tags :: HTML fragment containing additional form tags to use on the verify account form.
|
14
|
+
verify_account_autologin? :: Whether to autologin the user after successful account verification, true by default.
|
20
15
|
verify_account_button :: The text to use for the verify account button.
|
16
|
+
verify_account_email_recently_sent_error_flash :: The flash error to show if not sending verify account email because one has been sent recently.
|
17
|
+
verify_account_email_recently_sent_redirect :: Where to redirect if not sending verify account email because one has been sent recently.
|
21
18
|
verify_account_email_subject :: The subject to use for the verify account email.
|
22
|
-
verify_account_email_sent_redirect :: Where to redirect after sending the verify
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
verify_account_id_column :: The id column in the verify account keys table, should
|
29
|
-
be a foreign key referencing the accounts table.
|
30
|
-
verify_account_key_column :: The verify account key/token column in the verify
|
31
|
-
account keys table.
|
19
|
+
verify_account_email_sent_redirect :: Where to redirect after sending the verify account email.
|
20
|
+
verify_account_email_sent_notice_flash :: The flash notice to set after sending the verify account email.
|
21
|
+
verify_account_email_last_sent_column :: The email last sent column in the verify account keys table. nil by default, so a verify account email is always sent when requested by default.
|
22
|
+
verify_account_error_flash :: The flash error to show if no matching key is submitted when verifying an account.
|
23
|
+
verify_account_id_column :: The id column in the verify account keys table, should be a foreign key referencing the accounts table.
|
24
|
+
verify_account_key_column :: The verify account key/token column in the verify account keys table.
|
32
25
|
verify_account_key_param :: The parameter name to use for the verify account key.
|
33
26
|
verify_account_notice_flash :: The flash notice to show after verifying the account.
|
34
|
-
verify_account_resend_additional_form_tags :: HTML fragment containing additional form
|
35
|
-
tags to use on the page requesting
|
36
|
-
resending the verify account email.
|
27
|
+
verify_account_resend_additional_form_tags :: HTML fragment containing additional form tags to use on the page requesting resending the verify account email.
|
37
28
|
verify_account_resend_button :: The text to use for the verify account resend button.
|
38
29
|
verify_account_redirect :: Where to redirect after verifying the account.
|
39
|
-
verify_account_resend_error_flash :: The flash error to show if unable to resend a
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
verify_account_resend_route :: The route to the verify account resend action.
|
44
|
-
Defaults to +verify-account-resend+.
|
45
|
-
verify_account_route :: The route to the verify account action. Defaults to
|
46
|
-
+verify-account+.
|
30
|
+
verify_account_resend_error_flash :: The flash error to show if unable to resend a verify account email.
|
31
|
+
verify_account_resend_link :: The HTML to use for a link to the page to request the account verification email be resent.
|
32
|
+
verify_account_resend_route :: The route to the verify account resend action. Defaults to +verify-account-resend+.
|
33
|
+
verify_account_route :: The route to the verify account action. Defaults to +verify-account+.
|
47
34
|
verify_account_session_key :: The key in the session to hold the verify account key temporarily.
|
48
|
-
verify_account_set_password? :: Whether to ask for a password to be set on the verify account
|
49
|
-
|
50
|
-
stop asking for passwords to be set on the create account form.
|
35
|
+
verify_account_set_password? :: Whether to ask for a password to be set on the verify account form. Defaults to false. If set to true, will automatically stop asking for passwords to be set on the create account form.
|
36
|
+
verify_account_skip_resend_email_within :: The number of seconds before sending another verify account email, if +verify_account_email_last_sent_column+ is set.
|
51
37
|
verify_account_table :: The name of the verify account keys table.
|
52
38
|
|
53
39
|
== Auth Methods
|
54
40
|
|
55
|
-
account_from_verify_account_key(key) :: Retrieve the account using the given verify
|
56
|
-
account key, or return nil if no account
|
57
|
-
matches.
|
41
|
+
account_from_verify_account_key(key) :: Retrieve the account using the given verify account key, or return nil if no account matches.
|
58
42
|
after_verify_account :: Run arbitrary code after verifying the account.
|
59
43
|
after_verify_account_resend :: Run arbitrary code after resending a verify account email.
|
60
|
-
allow_resending_verify_account_email? :: Whether to allow sending the verify account email
|
61
|
-
for the account, true by default only if the
|
62
|
-
account has not been verified.
|
44
|
+
allow_resending_verify_account_email? :: Whether to allow sending the verify account email for the account, true by default only if the account has not been verified.
|
63
45
|
before_verify_account :: Run arbitrary code before verifying the account.
|
64
46
|
before_verify_account_resend :: Run arbitrary code before resending a verify account email.
|
47
|
+
before_verify_account_resend_route :: Run arbitrary code before handling a verify account resend route.
|
65
48
|
before_verify_account_route :: Run arbitrary code before handling a verify account route.
|
66
49
|
create_verify_account_key :: Add the verify account key data to the database.
|
67
50
|
create_verify_account_email :: A Mail::Message for the verify account email.
|
68
|
-
|
69
|
-
|
70
|
-
remove_verify_account_key :: Remove the verify account key for the current account,
|
71
|
-
|
72
|
-
resend_verify_account_view :: The HTML to use for page requesting resending the
|
73
|
-
verify account email.
|
51
|
+
get_verify_account_email_last_sent :: Get the last time a verify account email is sent, or nil if there is no last sent time.
|
52
|
+
get_verify_account_key(id) :: Get the verify account key for the given account id from the database.
|
53
|
+
remove_verify_account_key :: Remove the verify account key for the current account, run after successful account verification.
|
54
|
+
resend_verify_account_view :: The HTML to use for page requesting resending the verify account email.
|
74
55
|
send_verify_account_email :: Send the verify account email.
|
56
|
+
set_verify_account_email_last_sent :: Set the last time a verify account email is sent.
|
75
57
|
verify_account :: Verify the account by changing the status from unverified to open.
|
76
58
|
verify_account_email_body :: The body to use for the verify account email.
|
77
|
-
verify_account_email_link :: The link to the verify account form in the verify
|
78
|
-
|
79
|
-
verify_account_key_insert_hash :: The hash to insert into the verify account keys
|
80
|
-
table.
|
59
|
+
verify_account_email_link :: The link to the verify account form in the verify account email.
|
60
|
+
verify_account_key_insert_hash :: The hash to insert into the verify account keys table.
|
81
61
|
verify_account_key_value :: The value of the verify account key.
|
82
62
|
verify_account_view :: The HTML to use for the verify account form.
|
@@ -19,6 +19,8 @@ verify_login_change_autologin? :: Whether to autologin the user after successful
|
|
19
19
|
verify_login_change_button :: The text to use for the verify login change button.
|
20
20
|
verify_login_change_deadline_column :: The column name in the verify login change keys table storing the deadline after which the token will be ignored.
|
21
21
|
verify_login_change_deadline_interval :: The amount of time for which to allow users to verify login changes, 1 day by default.
|
22
|
+
verify_login_change_duplicate_account_error_flash :: The flash error message to show when attempting to verify a login change when the login is already taken.
|
23
|
+
verify_login_change_duplicate_account_redirect :: Where to redirect if not changing a login during verification because the new login is already taken.
|
22
24
|
verify_login_change_email_subject :: The subject to use for the verify login change email.
|
23
25
|
verify_login_change_error_flash :: The flash error to show if no matching key is submitted when verifying login change.
|
24
26
|
verify_login_change_id_column :: The id column in the verify login change keys table, should be a foreign key referencing the accounts table.
|
@@ -35,7 +37,9 @@ verify_login_change_table :: The name of the verify login change keys table.
|
|
35
37
|
|
36
38
|
account_from_verify_login_change_key(key) :: Retrieve the account using the given verify account key, or return nil if no account matches. Should also override verify_login_change_new_login if overriding this method.
|
37
39
|
after_verify_login_change :: Run arbitrary code after verifying the login change.
|
40
|
+
after_verify_login_change_email :: Run arbitrary code after sending verify login change email.
|
38
41
|
before_verify_login_change :: Run arbitrary code before verifying the login change.
|
42
|
+
before_verify_login_change_email :: Run arbitrary code before sending verify login change email.
|
39
43
|
before_verify_login_change_route :: Run arbitrary code before handling a verify login change route.
|
40
44
|
create_verify_login_change_email(login) :: A Mail::Message for the verify login change email.
|
41
45
|
create_verify_login_change_key(login) :: Add the verify login change key data to the database.
|
@@ -74,6 +74,10 @@ module Rodauth
|
|
74
74
|
private
|
75
75
|
|
76
76
|
def update_login(login)
|
77
|
+
_update_login(login)
|
78
|
+
end
|
79
|
+
|
80
|
+
def _update_login(login)
|
77
81
|
updated = nil
|
78
82
|
raised = raises_uniqueness_violation?{updated = update_account({login_column=>login}, account_ds.exclude(login_column=>login)) == 1}
|
79
83
|
if raised
|
@@ -4,7 +4,7 @@ module Rodauth
|
|
4
4
|
Feature.define(:disallow_common_passwords, :DisallowCommonPasswords) do
|
5
5
|
depends :login_password_requirements_base
|
6
6
|
|
7
|
-
auth_value_method :most_common_passwords_file, File.
|
7
|
+
auth_value_method :most_common_passwords_file, File.expand_path('../../../../dict/top-10_000-passwords.txt', __FILE__)
|
8
8
|
auth_value_method :password_is_one_of_the_most_common_message, "is one of the most common passwords"
|
9
9
|
auth_value_method :most_common_passwords, nil
|
10
10
|
|
@@ -0,0 +1,253 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Rodauth
|
4
|
+
Feature.define(:email_auth, :EmailAuth) do
|
5
|
+
depends :login, :email_base
|
6
|
+
|
7
|
+
notice_flash "An email has been sent to you with a link to login to your account", 'email_auth_email_sent'
|
8
|
+
error_flash "There was an error logging you in"
|
9
|
+
error_flash "There was an error requesting an email link to authenticate", 'email_auth_request'
|
10
|
+
error_flash "An email has recently been sent to you with a link to login", 'email_auth_email_recently_sent'
|
11
|
+
loaded_templates %w'email-auth email-auth-request-form email-auth-email'
|
12
|
+
|
13
|
+
view 'email-auth', 'Login'
|
14
|
+
additional_form_tags
|
15
|
+
additional_form_tags 'email_auth_request'
|
16
|
+
before 'email_auth_request'
|
17
|
+
after 'email_auth_request'
|
18
|
+
button 'Send Login Link Via Email', 'email_auth_request'
|
19
|
+
redirect(:email_auth_email_sent){default_post_email_redirect}
|
20
|
+
redirect(:email_auth_email_recently_sent){default_post_email_redirect}
|
21
|
+
|
22
|
+
auth_value_method :email_auth_deadline_column, :deadline
|
23
|
+
auth_value_method :email_auth_deadline_interval, {:days=>1}
|
24
|
+
auth_value_method :email_auth_email_subject, 'Login Link'
|
25
|
+
auth_value_method :email_auth_id_column, :id
|
26
|
+
auth_value_method :email_auth_key_column, :key
|
27
|
+
auth_value_method :email_auth_key_param, 'key'
|
28
|
+
auth_value_method :email_auth_email_last_sent_column, :email_last_sent
|
29
|
+
auth_value_method :email_auth_skip_resend_email_within, 300
|
30
|
+
auth_value_method :email_auth_table, :account_email_auth_keys
|
31
|
+
auth_value_method :no_matching_email_auth_key_message, "invalid email authentication key"
|
32
|
+
session_key :email_auth_session_key, :email_auth_key
|
33
|
+
|
34
|
+
auth_value_methods :force_email_auth?
|
35
|
+
|
36
|
+
auth_methods(
|
37
|
+
:create_email_auth_email,
|
38
|
+
:create_email_auth_key,
|
39
|
+
:email_auth_email_body,
|
40
|
+
:email_auth_email_link,
|
41
|
+
:email_auth_key_insert_hash,
|
42
|
+
:email_auth_key_value,
|
43
|
+
:email_auth_request_form,
|
44
|
+
:get_email_auth_key,
|
45
|
+
:get_email_auth_email_last_sent,
|
46
|
+
:remove_email_auth_key,
|
47
|
+
:send_email_auth_email,
|
48
|
+
:set_email_auth_email_last_sent
|
49
|
+
)
|
50
|
+
|
51
|
+
auth_private_methods :account_from_email_auth_key
|
52
|
+
|
53
|
+
route(:email_auth_request) do |r|
|
54
|
+
check_already_logged_in
|
55
|
+
before_email_auth_request_route
|
56
|
+
|
57
|
+
r.post do
|
58
|
+
if account_from_login(param(login_param)) && open_account?
|
59
|
+
_email_auth_request
|
60
|
+
else
|
61
|
+
set_redirect_error_status(no_matching_login_error_status)
|
62
|
+
set_redirect_error_flash email_auth_request_error_flash
|
63
|
+
end
|
64
|
+
|
65
|
+
redirect email_auth_email_sent_redirect
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
route do |r|
|
70
|
+
check_already_logged_in
|
71
|
+
before_email_auth_route
|
72
|
+
|
73
|
+
r.get do
|
74
|
+
if key = param_or_nil(email_auth_key_param)
|
75
|
+
session[email_auth_session_key] = key
|
76
|
+
redirect(r.path)
|
77
|
+
end
|
78
|
+
|
79
|
+
if key = session[email_auth_session_key]
|
80
|
+
if account_from_email_auth_key(key)
|
81
|
+
email_auth_view
|
82
|
+
else
|
83
|
+
session[email_auth_session_key] = nil
|
84
|
+
set_redirect_error_flash no_matching_email_auth_key_message
|
85
|
+
redirect require_login_redirect
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
r.post do
|
91
|
+
key = session[email_auth_session_key] || param(email_auth_key_param)
|
92
|
+
unless account_from_email_auth_key(key)
|
93
|
+
set_redirect_error_status(invalid_key_error_status)
|
94
|
+
set_redirect_error_flash email_auth_error_flash
|
95
|
+
redirect email_auth_email_sent_redirect
|
96
|
+
end
|
97
|
+
|
98
|
+
_login
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def create_email_auth_key
|
103
|
+
transaction do
|
104
|
+
if email_auth_key_value = get_email_auth_key(account_id)
|
105
|
+
set_email_auth_email_last_sent
|
106
|
+
@email_auth_key_value = email_auth_key_value
|
107
|
+
elsif e = raised_uniqueness_violation{email_auth_ds.insert(email_auth_key_insert_hash)}
|
108
|
+
# If inserting into the email auth table causes a violation, we can pull the
|
109
|
+
# existing email auth key from the table, or reraise.
|
110
|
+
raise e unless @email_auth_key_value = get_email_auth_key(account_id)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def set_email_auth_email_last_sent
|
116
|
+
email_auth_ds.update(email_auth_email_last_sent_column=>Sequel::CURRENT_TIMESTAMP) if email_auth_email_last_sent_column
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_email_auth_email_last_sent
|
120
|
+
if column = email_auth_email_last_sent_column
|
121
|
+
if ts = email_auth_ds.get(column)
|
122
|
+
convert_timestamp(ts)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def remove_email_auth_key
|
128
|
+
email_auth_ds.delete
|
129
|
+
end
|
130
|
+
|
131
|
+
def account_from_email_auth_key(key)
|
132
|
+
@account = _account_from_email_auth_key(key)
|
133
|
+
end
|
134
|
+
|
135
|
+
def send_email_auth_email
|
136
|
+
create_email_auth_email.deliver!
|
137
|
+
end
|
138
|
+
|
139
|
+
def email_auth_email_link
|
140
|
+
token_link(email_auth_route, email_auth_key_param, email_auth_key_value)
|
141
|
+
end
|
142
|
+
|
143
|
+
def get_email_auth_key(id)
|
144
|
+
ds = email_auth_ds(id)
|
145
|
+
ds.where(Sequel::CURRENT_TIMESTAMP > email_auth_deadline_column).delete
|
146
|
+
ds.get(email_auth_key_column)
|
147
|
+
end
|
148
|
+
|
149
|
+
def login_form_footer
|
150
|
+
footer = super
|
151
|
+
footer += @email_auth_request_form if @email_auth_request_form
|
152
|
+
footer
|
153
|
+
end
|
154
|
+
|
155
|
+
def email_auth_request_form
|
156
|
+
render('email-auth-request-form')
|
157
|
+
end
|
158
|
+
|
159
|
+
def after_login_entered_during_multi_phase_login
|
160
|
+
if force_email_auth?
|
161
|
+
# If the account does not have a password hash, just send the
|
162
|
+
# email link.
|
163
|
+
_email_auth_request
|
164
|
+
redirect email_auth_email_sent_redirect
|
165
|
+
else
|
166
|
+
# If the account has a password hash, allow password login, but
|
167
|
+
# show form below to also login via email link.
|
168
|
+
super
|
169
|
+
@email_auth_request_form = email_auth_request_form
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def use_multi_phase_login?
|
174
|
+
true
|
175
|
+
end
|
176
|
+
|
177
|
+
def force_email_auth?
|
178
|
+
get_password_hash.nil?
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
def email_auth_email_recently_sent?
|
184
|
+
(email_last_sent = get_email_auth_email_last_sent) && (Time.now - email_last_sent < email_auth_skip_resend_email_within)
|
185
|
+
end
|
186
|
+
|
187
|
+
def _email_auth_request
|
188
|
+
if email_auth_email_recently_sent?
|
189
|
+
set_redirect_error_flash email_auth_email_recently_sent_error_flash
|
190
|
+
redirect email_auth_email_recently_sent_redirect
|
191
|
+
end
|
192
|
+
|
193
|
+
generate_email_auth_key_value
|
194
|
+
transaction do
|
195
|
+
before_email_auth_request
|
196
|
+
create_email_auth_key
|
197
|
+
send_email_auth_email
|
198
|
+
after_email_auth_request
|
199
|
+
end
|
200
|
+
|
201
|
+
set_notice_flash email_auth_email_sent_notice_flash
|
202
|
+
end
|
203
|
+
|
204
|
+
attr_reader :email_auth_key_value
|
205
|
+
|
206
|
+
def after_login
|
207
|
+
# Remove the email auth key after any login, even if
|
208
|
+
# it is a password login. This is done to invalidate
|
209
|
+
# the email login when a user has a password and requests
|
210
|
+
# email authentication, but then remembers their password
|
211
|
+
# and doesn't need the link. At that point, the link
|
212
|
+
# that allows login access to the account becomes a
|
213
|
+
# security liability, and it is best to remove it.
|
214
|
+
remove_email_auth_key
|
215
|
+
super if defined?(super)
|
216
|
+
end
|
217
|
+
|
218
|
+
def after_close_account
|
219
|
+
remove_email_auth_key
|
220
|
+
super if defined?(super)
|
221
|
+
end
|
222
|
+
|
223
|
+
def generate_email_auth_key_value
|
224
|
+
@email_auth_key_value = random_key
|
225
|
+
end
|
226
|
+
|
227
|
+
def create_email_auth_email
|
228
|
+
create_email(email_auth_email_subject, email_auth_email_body)
|
229
|
+
end
|
230
|
+
|
231
|
+
def email_auth_email_body
|
232
|
+
render('email-auth-email')
|
233
|
+
end
|
234
|
+
|
235
|
+
def use_date_arithmetic?
|
236
|
+
super || db.database_type == :mysql
|
237
|
+
end
|
238
|
+
|
239
|
+
def email_auth_key_insert_hash
|
240
|
+
hash = {email_auth_id_column=>account_id, email_auth_key_column=>email_auth_key_value}
|
241
|
+
set_deadline_value(hash, email_auth_deadline_column, email_auth_deadline_interval)
|
242
|
+
hash
|
243
|
+
end
|
244
|
+
|
245
|
+
def email_auth_ds(id=account_id)
|
246
|
+
db[email_auth_table].where(email_auth_id_column=>id)
|
247
|
+
end
|
248
|
+
|
249
|
+
def _account_from_email_auth_key(token)
|
250
|
+
account_from_key(token, account_open_status_value){|id| get_email_auth_key(id)}
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|