rodauth 0.10.0 → 1.0.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 +146 -0
- data/README.rdoc +644 -220
- data/Rakefile +99 -11
- data/doc/account_expiration.rdoc +55 -0
- data/doc/base.rdoc +104 -0
- data/doc/change_login.rdoc +29 -0
- data/doc/change_password.rdoc +26 -0
- data/doc/close_account.rdoc +31 -0
- data/doc/confirm_password.rdoc +22 -0
- data/doc/create_account.rdoc +34 -0
- data/doc/disallow_password_reuse.rdoc +37 -0
- data/doc/email_base.rdoc +19 -0
- data/doc/jwt.rdoc +35 -0
- data/doc/lockout.rdoc +83 -0
- data/doc/login.rdoc +27 -0
- data/doc/login_password_requirements_base.rdoc +50 -0
- data/doc/logout.rdoc +21 -0
- data/doc/otp.rdoc +100 -0
- data/doc/password_complexity.rdoc +50 -0
- data/doc/password_expiration.rdoc +52 -0
- data/doc/password_grace_period.rdoc +10 -0
- data/doc/recovery_codes.rdoc +60 -0
- data/doc/release_notes/1.0.0.txt +443 -0
- data/doc/remember.rdoc +82 -0
- data/doc/reset_password.rdoc +70 -0
- data/doc/session_expiration.rdoc +27 -0
- data/doc/single_session.rdoc +43 -0
- data/doc/sms_codes.rdoc +119 -0
- data/doc/two_factor_base.rdoc +27 -0
- data/doc/verify_account.rdoc +70 -0
- data/doc/verify_account_grace_period.rdoc +15 -0
- data/doc/verify_change_login.rdoc +9 -0
- data/lib/roda/plugins/rodauth.rb +3 -262
- data/lib/rodauth.rb +260 -0
- data/lib/rodauth/features/account_expiration.rb +108 -0
- data/lib/rodauth/features/base.rb +479 -0
- data/lib/rodauth/features/change_login.rb +77 -0
- data/lib/rodauth/features/change_password.rb +66 -0
- data/lib/rodauth/features/close_account.rb +82 -0
- data/lib/rodauth/features/confirm_password.rb +51 -0
- data/lib/rodauth/features/create_account.rb +128 -0
- data/lib/rodauth/features/disallow_password_reuse.rb +82 -0
- data/lib/rodauth/features/email_base.rb +63 -0
- data/lib/rodauth/features/jwt.rb +151 -0
- data/lib/rodauth/features/lockout.rb +262 -0
- data/lib/rodauth/features/login.rb +61 -0
- data/lib/rodauth/features/login_password_requirements_base.rb +123 -0
- data/lib/rodauth/features/logout.rb +37 -0
- data/lib/rodauth/features/otp.rb +338 -0
- data/lib/rodauth/features/password_complexity.rb +89 -0
- data/lib/rodauth/features/password_expiration.rb +111 -0
- data/lib/rodauth/features/password_grace_period.rb +46 -0
- data/lib/rodauth/features/recovery_codes.rb +240 -0
- data/lib/rodauth/features/remember.rb +200 -0
- data/lib/rodauth/features/reset_password.rb +207 -0
- data/lib/rodauth/features/session_expiration.rb +55 -0
- data/lib/rodauth/features/single_session.rb +87 -0
- data/lib/rodauth/features/sms_codes.rb +498 -0
- data/lib/rodauth/features/two_factor_base.rb +135 -0
- data/lib/rodauth/features/verify_account.rb +232 -0
- data/lib/rodauth/features/verify_account_grace_period.rb +76 -0
- data/lib/rodauth/features/verify_change_login.rb +20 -0
- data/lib/rodauth/migrations.rb +130 -0
- data/lib/rodauth/version.rb +9 -0
- data/spec/account_expiration_spec.rb +90 -0
- data/spec/all.rb +1 -0
- data/spec/change_login_spec.rb +149 -0
- data/spec/change_password_spec.rb +177 -0
- data/spec/close_account_spec.rb +162 -0
- data/spec/confirm_password_spec.rb +70 -0
- data/spec/create_account_spec.rb +127 -0
- data/spec/disallow_password_reuse_spec.rb +84 -0
- data/spec/lockout_spec.rb +228 -0
- data/spec/login_spec.rb +188 -0
- data/spec/migrate/001_tables.rb +103 -16
- data/spec/migrate/002_account_password_hash_column.rb +11 -0
- data/spec/migrate_password/001_tables.rb +60 -42
- data/spec/migrate_travis/001_tables.rb +116 -0
- data/spec/password_complexity_spec.rb +108 -0
- data/spec/password_expiration_spec.rb +243 -0
- data/spec/password_grace_period_spec.rb +93 -0
- data/spec/remember_spec.rb +424 -0
- data/spec/reset_password_spec.rb +185 -0
- data/spec/rodauth_spec.rb +57 -980
- data/spec/session_expiration_spec.rb +58 -0
- data/spec/single_session_spec.rb +107 -0
- data/spec/spec_helper.rb +202 -0
- data/spec/two_factor_spec.rb +1310 -0
- data/spec/verify_account_grace_period_spec.rb +135 -0
- data/spec/verify_account_spec.rb +142 -0
- data/spec/verify_change_login_spec.rb +46 -0
- data/spec/views/login.str +2 -2
- data/templates/add-recovery-codes.str +2 -0
- data/templates/button.str +5 -0
- data/templates/change-login.str +5 -18
- data/templates/change-password.str +6 -14
- data/templates/close-account.str +3 -6
- data/templates/confirm-password.str +4 -14
- data/templates/create-account.str +6 -30
- data/templates/login-confirm-field.str +6 -0
- data/templates/login-field.str +6 -0
- data/templates/login.str +5 -19
- data/templates/logout.str +2 -6
- data/templates/otp-auth-code-field.str +6 -0
- data/templates/otp-auth.str +8 -0
- data/templates/otp-disable.str +6 -0
- data/templates/otp-setup.str +21 -0
- data/templates/password-confirm-field.str +6 -0
- data/templates/password-field.str +6 -0
- data/templates/recovery-auth.str +12 -0
- data/templates/recovery-codes.str +6 -0
- data/templates/remember.str +8 -12
- data/templates/reset-password-request.str +2 -2
- data/templates/reset-password.str +4 -18
- data/templates/sms-auth.str +6 -0
- data/templates/sms-code-field.str +6 -0
- data/templates/sms-confirm.str +7 -0
- data/templates/sms-disable.str +7 -0
- data/templates/sms-request.str +5 -0
- data/templates/sms-setup.str +12 -0
- data/templates/unlock-account-request.str +3 -7
- data/templates/unlock-account.str +4 -7
- data/templates/verify-account-resend.str +2 -2
- data/templates/verify-account.str +2 -6
- metadata +191 -29
- data/lib/roda/plugins/rodauth/base.rb +0 -428
- data/lib/roda/plugins/rodauth/change_login.rb +0 -48
- data/lib/roda/plugins/rodauth/change_password.rb +0 -42
- data/lib/roda/plugins/rodauth/close_account.rb +0 -42
- data/lib/roda/plugins/rodauth/create_account.rb +0 -92
- data/lib/roda/plugins/rodauth/lockout.rb +0 -292
- data/lib/roda/plugins/rodauth/login.rb +0 -81
- data/lib/roda/plugins/rodauth/logout.rb +0 -36
- data/lib/roda/plugins/rodauth/remember.rb +0 -226
- data/lib/roda/plugins/rodauth/reset_password.rb +0 -205
- data/lib/roda/plugins/rodauth/verify_account.rb +0 -228
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Rodauth
|
|
4
|
+
TwoFactorBase = Feature.define(:two_factor_base) do
|
|
5
|
+
after :two_factor_authentication
|
|
6
|
+
|
|
7
|
+
redirect :two_factor_auth
|
|
8
|
+
redirect :two_factor_already_authenticated
|
|
9
|
+
|
|
10
|
+
notice_flash "You have been authenticated via 2nd factor", "two_factor_auth"
|
|
11
|
+
|
|
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'
|
|
15
|
+
|
|
16
|
+
auth_value_method :two_factor_session_key, :two_factor_auth
|
|
17
|
+
auth_value_method :two_factor_setup_session_key, :two_factor_auth_setup
|
|
18
|
+
auth_value_method :two_factor_need_setup_redirect, nil
|
|
19
|
+
|
|
20
|
+
auth_value_methods(
|
|
21
|
+
:two_factor_auth_required_redirect,
|
|
22
|
+
:two_factor_modifications_require_password?
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
auth_methods(
|
|
26
|
+
:two_factor_authenticated?,
|
|
27
|
+
:two_factor_remove,
|
|
28
|
+
:two_factor_remove_auth_failures,
|
|
29
|
+
:two_factor_remove_session,
|
|
30
|
+
:two_factor_update_session
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def two_factor_modifications_require_password?
|
|
34
|
+
modifications_require_password?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def authenticated?
|
|
38
|
+
super
|
|
39
|
+
two_factor_authenticated? if two_factor_authentication_setup?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def require_authentication
|
|
43
|
+
super
|
|
44
|
+
require_two_factor_authenticated if two_factor_authentication_setup?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def require_two_factor_setup
|
|
48
|
+
unless uses_two_factor_authentication?
|
|
49
|
+
set_redirect_error_flash two_factor_not_setup_error_flash
|
|
50
|
+
redirect two_factor_need_setup_redirect
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def require_two_factor_not_authenticated
|
|
55
|
+
if two_factor_authenticated?
|
|
56
|
+
set_redirect_error_flash two_factor_already_authenticated_error_flash
|
|
57
|
+
redirect two_factor_already_authenticated_redirect
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def require_two_factor_authenticated
|
|
62
|
+
unless two_factor_authenticated?
|
|
63
|
+
set_redirect_error_flash two_factor_need_authentication_error_flash
|
|
64
|
+
redirect _two_factor_auth_required_redirect
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def two_factor_remove_auth_failures
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def two_factor_auth_required_redirect
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def two_factor_auth_fallback_redirect
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def two_factor_password_match?(password)
|
|
81
|
+
if two_factor_modifications_require_password?
|
|
82
|
+
password_match?(password)
|
|
83
|
+
else
|
|
84
|
+
true
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def two_factor_authenticated?
|
|
89
|
+
!!session[two_factor_session_key]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def two_factor_authentication_setup?
|
|
93
|
+
false
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def uses_two_factor_authentication?
|
|
97
|
+
return false unless logged_in?
|
|
98
|
+
session[two_factor_setup_session_key] = two_factor_authentication_setup? unless session.has_key?(two_factor_setup_session_key)
|
|
99
|
+
session[two_factor_setup_session_key]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def two_factor_remove
|
|
103
|
+
nil
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def after_close_account
|
|
109
|
+
super if defined?(super)
|
|
110
|
+
two_factor_remove
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def two_factor_authenticate(type)
|
|
114
|
+
two_factor_update_session(type)
|
|
115
|
+
two_factor_remove_auth_failures
|
|
116
|
+
after_two_factor_authentication
|
|
117
|
+
set_notice_flash two_factor_auth_notice_flash
|
|
118
|
+
redirect two_factor_auth_redirect
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def two_factor_remove_session
|
|
122
|
+
session.delete(two_factor_session_key)
|
|
123
|
+
session[two_factor_setup_session_key] = false
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def two_factor_update_session(type)
|
|
127
|
+
session[two_factor_session_key] = type
|
|
128
|
+
session[two_factor_setup_session_key] = true
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def _two_factor_auth_required_redirect
|
|
132
|
+
two_factor_auth_required_redirect || two_factor_auth_fallback_redirect || default_redirect
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Rodauth
|
|
4
|
+
VerifyAccount = Feature.define(:verify_account) do
|
|
5
|
+
depends :login, :create_account, :email_base
|
|
6
|
+
|
|
7
|
+
error_flash "Unable to verify account"
|
|
8
|
+
error_flash "Unable to resend verify account email", 'verify_account_resend'
|
|
9
|
+
notice_flash "Your account has been verified"
|
|
10
|
+
notice_flash "An email has been sent to you with a link to verify your account", 'verify_account_email_sent'
|
|
11
|
+
view 'verify-account', 'Verify Account'
|
|
12
|
+
view 'verify-account-resend', 'Resend Verification Email', 'resend_verify_account'
|
|
13
|
+
additional_form_tags
|
|
14
|
+
additional_form_tags 'verify_account_resend'
|
|
15
|
+
after
|
|
16
|
+
after 'verify_account_email_resend'
|
|
17
|
+
before
|
|
18
|
+
before 'verify_account_email_resend'
|
|
19
|
+
button 'Verify Account'
|
|
20
|
+
button 'Send Verification Email Again', 'verify_account_resend'
|
|
21
|
+
redirect
|
|
22
|
+
redirect(:verify_account_email_sent){require_login_redirect}
|
|
23
|
+
|
|
24
|
+
auth_value_method :no_matching_verify_account_key_message, "invalid verify account key"
|
|
25
|
+
auth_value_method :attempt_to_create_unverified_account_notice_message, "The account you tried to create is currently awaiting verification"
|
|
26
|
+
auth_value_method :attempt_to_login_to_unverified_account_notice_message, "The account you tried to login with is currently awaiting verification"
|
|
27
|
+
auth_value_method :verify_account_email_subject, 'Verify Account'
|
|
28
|
+
auth_value_method :verify_account_key_param, 'key'
|
|
29
|
+
auth_value_method :verify_account_autologin?, true
|
|
30
|
+
auth_value_method :verify_account_table, :account_verification_keys
|
|
31
|
+
auth_value_method :verify_account_id_column, :id
|
|
32
|
+
auth_value_method :verify_account_key_column, :key
|
|
33
|
+
|
|
34
|
+
auth_value_methods :verify_account_key_value
|
|
35
|
+
|
|
36
|
+
auth_methods(
|
|
37
|
+
:create_verify_account_key,
|
|
38
|
+
:create_verify_account_email,
|
|
39
|
+
:get_verify_account_key,
|
|
40
|
+
:remove_verify_account_key,
|
|
41
|
+
:resend_verify_account_view,
|
|
42
|
+
:send_verify_account_email,
|
|
43
|
+
:verify_account,
|
|
44
|
+
:verify_account_email_body,
|
|
45
|
+
:verify_account_email_link,
|
|
46
|
+
:verify_account_key_insert_hash
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
auth_private_methods(
|
|
50
|
+
:account_from_verify_account_key
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
route(:verify_account_resend) do |r|
|
|
54
|
+
verify_account_check_already_logged_in
|
|
55
|
+
before_verify_account_resend_route
|
|
56
|
+
|
|
57
|
+
r.post do
|
|
58
|
+
if account_from_login(param(login_param)) && !open_account?
|
|
59
|
+
before_verify_account_email_resend
|
|
60
|
+
if verify_account_email_resend
|
|
61
|
+
after_verify_account_email_resend
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
set_notice_flash verify_account_email_sent_notice_flash
|
|
65
|
+
else
|
|
66
|
+
set_redirect_error_flash verify_account_resend_error_flash
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
redirect verify_account_email_sent_redirect
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
route do |r|
|
|
74
|
+
verify_account_check_already_logged_in
|
|
75
|
+
before_verify_account_route
|
|
76
|
+
|
|
77
|
+
r.get do
|
|
78
|
+
if key = param_or_nil(verify_account_key_param)
|
|
79
|
+
if account_from_verify_account_key(key)
|
|
80
|
+
verify_account_view
|
|
81
|
+
else
|
|
82
|
+
set_redirect_error_flash no_matching_verify_account_key_message
|
|
83
|
+
redirect require_login_redirect
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
r.post do
|
|
89
|
+
key = param(verify_account_key_param)
|
|
90
|
+
unless account_from_verify_account_key(key)
|
|
91
|
+
set_redirect_error_flash verify_account_error_flash
|
|
92
|
+
redirect verify_account_redirect
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
transaction do
|
|
96
|
+
before_verify_account
|
|
97
|
+
verify_account
|
|
98
|
+
remove_verify_account_key
|
|
99
|
+
after_verify_account
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if verify_account_autologin?
|
|
103
|
+
update_session
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
set_notice_flash verify_account_notice_flash
|
|
107
|
+
redirect verify_account_redirect
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def remove_verify_account_key
|
|
112
|
+
verify_account_ds.delete
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def verify_account
|
|
116
|
+
update_account(account_status_column=>account_open_status_value) == 1
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def verify_account_email_resend
|
|
120
|
+
if @verify_account_key_value = get_verify_account_key(account_id)
|
|
121
|
+
send_verify_account_email
|
|
122
|
+
true
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def create_account_notice_flash
|
|
127
|
+
verify_account_email_sent_notice_flash
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def new_account(login)
|
|
131
|
+
if account_from_login(login)
|
|
132
|
+
set_error_flash attempt_to_create_unverified_account_notice_message
|
|
133
|
+
response.write resend_verify_account_view
|
|
134
|
+
request.halt
|
|
135
|
+
end
|
|
136
|
+
super
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def account_from_verify_account_key(key)
|
|
140
|
+
@account = _account_from_verify_account_key(key)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def account_initial_status_value
|
|
144
|
+
account_unverified_status_value
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def send_verify_account_email
|
|
148
|
+
create_verify_account_email.deliver!
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def verify_account_email_link
|
|
152
|
+
token_link(verify_account_route, verify_account_key_param, verify_account_key_value)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def get_verify_account_key(id)
|
|
156
|
+
verify_account_ds(id).get(verify_account_key_column)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def skip_status_checks?
|
|
160
|
+
false
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def create_account_autologin?
|
|
164
|
+
false
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
private
|
|
168
|
+
|
|
169
|
+
attr_reader :verify_account_key_value
|
|
170
|
+
|
|
171
|
+
def before_login_attempt
|
|
172
|
+
unless open_account?
|
|
173
|
+
set_error_flash attempt_to_login_to_unverified_account_notice_message
|
|
174
|
+
response.write resend_verify_account_view
|
|
175
|
+
request.halt
|
|
176
|
+
end
|
|
177
|
+
super
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def after_create_account
|
|
181
|
+
setup_account_verification
|
|
182
|
+
super
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def setup_account_verification
|
|
186
|
+
generate_verify_account_key_value
|
|
187
|
+
create_verify_account_key
|
|
188
|
+
send_verify_account_email
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def verify_account_check_already_logged_in
|
|
192
|
+
check_already_logged_in
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def generate_verify_account_key_value
|
|
196
|
+
@verify_account_key_value = random_key
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def create_verify_account_key
|
|
200
|
+
ds = verify_account_ds
|
|
201
|
+
transaction do
|
|
202
|
+
if ds.empty?
|
|
203
|
+
if e = raised_uniqueness_violation{ds.insert(verify_account_key_insert_hash)}
|
|
204
|
+
# If inserting into the verify account table causes a violation, we can pull the
|
|
205
|
+
# key from the verify account table, or reraise.
|
|
206
|
+
raise e unless @verify_account_key_value = get_verify_account_key(account_id)
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def verify_account_key_insert_hash
|
|
213
|
+
{verify_account_id_column=>account_id, verify_account_key_column=>verify_account_key_value}
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def create_verify_account_email
|
|
217
|
+
create_email(verify_account_email_subject, verify_account_email_body)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def verify_account_email_body
|
|
221
|
+
render('verify-account-email')
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def verify_account_ds(id=account_id)
|
|
225
|
+
db[verify_account_table].where(verify_account_id_column=>id)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def _account_from_verify_account_key(token)
|
|
229
|
+
account_from_key(token, account_unverified_status_value){|id| get_verify_account_key(id)}
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Rodauth
|
|
4
|
+
VerifyAccountGracePeriod = Feature.define(:verify_account_grace_period) do
|
|
5
|
+
depends :verify_account
|
|
6
|
+
error_flash "Cannot change login for unverified account. Please verify this account before changing the login.", "unverified_change_login"
|
|
7
|
+
redirect :unverified_change_login
|
|
8
|
+
|
|
9
|
+
auth_value_method :verification_requested_at_column, :requested_at
|
|
10
|
+
auth_value_method :unverified_account_session_key, :unverified_account
|
|
11
|
+
auth_value_method :verify_account_grace_period, 86400
|
|
12
|
+
|
|
13
|
+
auth_methods(
|
|
14
|
+
:account_in_unverified_grace_period?
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
def verified_account?
|
|
18
|
+
logged_in? && !session[unverified_account_session_key]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create_account_autologin?
|
|
22
|
+
true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def open_account?
|
|
26
|
+
super || account_in_unverified_grace_period?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def after_close_account
|
|
32
|
+
super if defined?(super)
|
|
33
|
+
verify_account_ds.delete
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def before_change_login_route
|
|
37
|
+
unless verified_account?
|
|
38
|
+
set_redirect_error_flash unverified_change_login_error_flash
|
|
39
|
+
redirect unverified_change_login_redirect
|
|
40
|
+
end
|
|
41
|
+
super if defined?(super)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def verify_account_check_already_logged_in
|
|
45
|
+
nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def account_session_status_filter
|
|
49
|
+
s = super
|
|
50
|
+
if verify_account_grace_period
|
|
51
|
+
grace_period_ds = db[verify_account_table].
|
|
52
|
+
select(verify_account_id_column).
|
|
53
|
+
where((Sequel.date_add(verification_requested_at_column, :seconds=>verify_account_grace_period) > Sequel::CURRENT_TIMESTAMP))
|
|
54
|
+
s = Sequel.|(s, Sequel.expr(account_status_column=>account_unverified_status_value) & {account_id_column => grace_period_ds})
|
|
55
|
+
end
|
|
56
|
+
s
|
|
57
|
+
end
|
|
58
|
+
|
|
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
|
+
def account_in_unverified_grace_period?
|
|
67
|
+
account[account_status_column] == account_unverified_status_value &&
|
|
68
|
+
verify_account_grace_period &&
|
|
69
|
+
!verify_account_ds.where(Sequel.date_add(verification_requested_at_column, :seconds=>verify_account_grace_period) > Sequel::CURRENT_TIMESTAMP).empty?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def use_date_arithmetic?
|
|
73
|
+
true
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Rodauth
|
|
4
|
+
VerifyChangeLogin = Feature.define(:verify_change_login) do
|
|
5
|
+
depends :change_login, :verify_account_grace_period
|
|
6
|
+
|
|
7
|
+
def change_login_notice_flash
|
|
8
|
+
"#{super}. #{verify_account_email_sent_notice_flash}"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def after_change_login
|
|
14
|
+
super
|
|
15
|
+
update_account(account_status_column=>account_unverified_status_value)
|
|
16
|
+
setup_account_verification
|
|
17
|
+
session[unverified_account_session_key] = true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|