rodauth 1.9.0 → 1.10.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 +20 -0
- data/README.rdoc +14 -3
- data/Rakefile +2 -2
- data/doc/base.rdoc +1 -1
- data/doc/internals.rdoc +222 -0
- data/doc/release_notes/1.10.0.txt +80 -0
- data/doc/reset_password.rdoc +8 -2
- data/doc/verify_account.rdoc +7 -1
- data/doc/verify_change_login.rdoc +8 -6
- data/doc/verify_login_change.rdoc +52 -0
- data/lib/rodauth/features/account_expiration.rb +1 -1
- data/lib/rodauth/features/base.rb +1 -1
- data/lib/rodauth/features/change_login.rb +9 -2
- data/lib/rodauth/features/change_password.rb +1 -1
- data/lib/rodauth/features/close_account.rb +1 -1
- data/lib/rodauth/features/confirm_password.rb +1 -1
- data/lib/rodauth/features/create_account.rb +1 -1
- data/lib/rodauth/features/disallow_password_reuse.rb +1 -1
- data/lib/rodauth/features/email_base.rb +6 -2
- data/lib/rodauth/features/http_basic_auth.rb +1 -1
- data/lib/rodauth/features/jwt.rb +1 -1
- data/lib/rodauth/features/lockout.rb +1 -1
- data/lib/rodauth/features/login.rb +1 -1
- data/lib/rodauth/features/login_password_requirements_base.rb +1 -1
- data/lib/rodauth/features/logout.rb +1 -1
- data/lib/rodauth/features/otp.rb +1 -1
- data/lib/rodauth/features/password_complexity.rb +1 -1
- data/lib/rodauth/features/password_expiration.rb +1 -1
- data/lib/rodauth/features/password_grace_period.rb +1 -1
- data/lib/rodauth/features/recovery_codes.rb +1 -1
- data/lib/rodauth/features/remember.rb +1 -1
- data/lib/rodauth/features/reset_password.rb +22 -4
- data/lib/rodauth/features/session_expiration.rb +1 -1
- data/lib/rodauth/features/single_session.rb +1 -1
- data/lib/rodauth/features/sms_codes.rb +1 -1
- data/lib/rodauth/features/two_factor_base.rb +1 -1
- data/lib/rodauth/features/update_password_hash.rb +1 -1
- data/lib/rodauth/features/verify_account.rb +23 -5
- data/lib/rodauth/features/verify_account_grace_period.rb +1 -1
- data/lib/rodauth/features/verify_change_login.rb +1 -1
- data/lib/rodauth/features/verify_login_change.rb +189 -0
- data/lib/rodauth/version.rb +1 -1
- data/lib/rodauth.rb +16 -2
- data/spec/migrate/001_tables.rb +10 -0
- data/spec/migrate_travis/001_tables.rb +7 -0
- data/spec/reset_password_spec.rb +8 -1
- data/spec/rodauth_spec.rb +27 -0
- data/spec/spec_helper.rb +11 -7
- data/spec/verify_account_grace_period_spec.rb +36 -0
- data/spec/verify_account_spec.rb +6 -0
- data/spec/verify_login_change_spec.rb +179 -0
- data/templates/reset-password-request.str +3 -3
- data/templates/verify-account-resend.str +3 -3
- data/templates/verify-login-change-email.str +9 -0
- data/templates/verify-login-change.str +5 -0
- metadata +12 -2
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
module Rodauth
|
4
|
-
|
4
|
+
Feature.define(:email_base, :EmailBase) do
|
5
5
|
auth_value_method :email_subject_prefix, nil
|
6
6
|
auth_value_method :require_mail?, true
|
7
7
|
auth_value_method :token_separator, "_"
|
@@ -23,9 +23,13 @@ module Rodauth
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def create_email(subject, body)
|
26
|
+
create_email_to(email_to, subject, body)
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_email_to(to, subject, body)
|
26
30
|
m = Mail.new
|
27
31
|
m.from = email_from
|
28
|
-
m.to =
|
32
|
+
m.to = to
|
29
33
|
m.subject = "#{email_subject_prefix}#{subject}"
|
30
34
|
m.body = body
|
31
35
|
m
|
data/lib/rodauth/features/jwt.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'jwt'
|
4
4
|
|
5
5
|
module Rodauth
|
6
|
-
|
6
|
+
Feature.define(:jwt, :Jwt) do
|
7
7
|
auth_value_method :invalid_jwt_format_error_message, "invalid JWT format or claim in Authorization header"
|
8
8
|
auth_value_method :json_non_post_error_message, 'non-POST method used in JSON API'
|
9
9
|
auth_value_method :json_not_accepted_error_message, 'Unsupported Accept header. Must accept "application/json" or compatible content type'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
module Rodauth
|
4
|
-
|
4
|
+
Feature.define(:login_password_requirements_base, :LoginPasswordRequirementsBase) do
|
5
5
|
auth_value_method :login_confirm_param, 'login-confirm'
|
6
6
|
auth_value_method :login_minimum_length, 3
|
7
7
|
auth_value_method :login_maximum_length, 255
|
data/lib/rodauth/features/otp.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
module Rodauth
|
4
|
-
|
4
|
+
Feature.define(:password_complexity, :PasswordComplexity) do
|
5
5
|
depends :login_password_requirements_base
|
6
6
|
|
7
7
|
auth_value_method :password_dictionary_file, nil
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
module Rodauth
|
4
|
-
|
4
|
+
Feature.define(:password_expiration, :PasswordExpiration) do
|
5
5
|
depends :login, :change_password
|
6
6
|
|
7
7
|
error_flash "Your password has expired and needs to be changed"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
module Rodauth
|
4
|
-
|
4
|
+
Feature.define(:password_grace_period, :PasswordGracePeriod) do
|
5
5
|
auth_value_method :password_grace_period, 300
|
6
6
|
auth_value_method :last_password_entry_session_key, :last_password_entry
|
7
7
|
|
@@ -1,15 +1,16 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
module Rodauth
|
4
|
-
|
4
|
+
Feature.define(:reset_password, :ResetPassword) do
|
5
5
|
depends :login, :email_base, :login_password_requirements_base
|
6
6
|
|
7
7
|
notice_flash "Your password has been reset"
|
8
8
|
notice_flash "An email has been sent to you with a link to reset the password for your account", 'reset_password_email_sent'
|
9
9
|
error_flash "There was an error resetting your password"
|
10
10
|
error_flash "There was an error requesting a password reset", 'reset_password_request'
|
11
|
-
loaded_templates %w'reset-password password-field password-confirm-field reset-password-email'
|
11
|
+
loaded_templates %w'reset-password-request reset-password password-field password-confirm-field reset-password-email'
|
12
12
|
view 'reset-password', 'Reset Password'
|
13
|
+
view 'reset-password-request', 'Request Password Reset', 'reset_password_request'
|
13
14
|
additional_form_tags
|
14
15
|
additional_form_tags 'reset_password_request'
|
15
16
|
before
|
@@ -32,12 +33,13 @@ module Rodauth
|
|
32
33
|
auth_value_method :reset_password_key_column, :key
|
33
34
|
auth_value_method :reset_password_session_key, :reset_password_key
|
34
35
|
|
35
|
-
auth_value_methods :reset_password_email_sent_redirect
|
36
|
+
auth_value_methods :reset_password_email_sent_redirect, :reset_password_request_link
|
36
37
|
|
37
38
|
auth_methods(
|
38
39
|
:create_reset_password_key,
|
39
40
|
:create_reset_password_email,
|
40
41
|
:get_reset_password_key,
|
42
|
+
:login_failed_reset_password_request_form,
|
41
43
|
:remove_reset_password_key,
|
42
44
|
:reset_password_email_body,
|
43
45
|
:reset_password_email_link,
|
@@ -53,6 +55,10 @@ module Rodauth
|
|
53
55
|
check_already_logged_in
|
54
56
|
before_reset_password_request_route
|
55
57
|
|
58
|
+
r.get do
|
59
|
+
reset_password_request_view
|
60
|
+
end
|
61
|
+
|
56
62
|
r.post do
|
57
63
|
if account_from_login(param(login_param)) && open_account?
|
58
64
|
generate_reset_password_key_value
|
@@ -173,13 +179,21 @@ module Rodauth
|
|
173
179
|
password_reset_ds(id).get(reset_password_key_column)
|
174
180
|
end
|
175
181
|
|
182
|
+
def login_form_footer
|
183
|
+
super + reset_password_request_link
|
184
|
+
end
|
185
|
+
|
186
|
+
def reset_password_request_link
|
187
|
+
"<p><a href=\"#{prefix}/#{reset_password_request_route}\">Forgot Password?</a></p>"
|
188
|
+
end
|
189
|
+
|
176
190
|
private
|
177
191
|
|
178
192
|
attr_reader :reset_password_key_value
|
179
193
|
|
180
194
|
def after_login_failure
|
181
195
|
unless only_json?
|
182
|
-
@login_form_header =
|
196
|
+
@login_form_header = login_failed_reset_password_request_form
|
183
197
|
end
|
184
198
|
super
|
185
199
|
end
|
@@ -197,6 +211,10 @@ module Rodauth
|
|
197
211
|
create_email(reset_password_email_subject, reset_password_email_body)
|
198
212
|
end
|
199
213
|
|
214
|
+
def login_failed_reset_password_request_form
|
215
|
+
render("reset-password-request")
|
216
|
+
end
|
217
|
+
|
200
218
|
def reset_password_email_body
|
201
219
|
render('reset-password-email')
|
202
220
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
module Rodauth
|
4
|
-
|
4
|
+
Feature.define(:session_expiration, :SessionExpiration) do
|
5
5
|
error_flash "This session has expired, please login again."
|
6
6
|
|
7
7
|
auth_value_method :max_session_lifetime, 86400
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
module Rodauth
|
4
|
-
|
4
|
+
Feature.define(:verify_account, :VerifyAccount) do
|
5
5
|
depends :login, :create_account, :email_base
|
6
6
|
|
7
7
|
error_flash "Unable to verify account"
|
@@ -33,9 +33,10 @@ module Rodauth
|
|
33
33
|
auth_value_method :verify_account_key_column, :key
|
34
34
|
auth_value_method :verify_account_session_key, :verify_account_key
|
35
35
|
|
36
|
-
auth_value_methods :
|
36
|
+
auth_value_methods :verify_account_resend_link
|
37
37
|
|
38
38
|
auth_methods(
|
39
|
+
:allow_resending_verify_account_email?,
|
39
40
|
:create_verify_account_key,
|
40
41
|
:create_verify_account_email,
|
41
42
|
:get_verify_account_key,
|
@@ -45,7 +46,8 @@ module Rodauth
|
|
45
46
|
:verify_account,
|
46
47
|
:verify_account_email_body,
|
47
48
|
:verify_account_email_link,
|
48
|
-
:verify_account_key_insert_hash
|
49
|
+
:verify_account_key_insert_hash,
|
50
|
+
:verify_account_key_value
|
49
51
|
)
|
50
52
|
|
51
53
|
auth_private_methods(
|
@@ -56,8 +58,12 @@ module Rodauth
|
|
56
58
|
verify_account_check_already_logged_in
|
57
59
|
before_verify_account_resend_route
|
58
60
|
|
61
|
+
r.get do
|
62
|
+
resend_verify_account_view
|
63
|
+
end
|
64
|
+
|
59
65
|
r.post do
|
60
|
-
if account_from_login(param(login_param)) &&
|
66
|
+
if account_from_login(param(login_param)) && allow_resending_verify_account_email?
|
61
67
|
before_verify_account_email_resend
|
62
68
|
if verify_account_email_resend
|
63
69
|
after_verify_account_email_resend
|
@@ -119,6 +125,10 @@ module Rodauth
|
|
119
125
|
end
|
120
126
|
end
|
121
127
|
|
128
|
+
def allow_resending_verify_account_email?
|
129
|
+
account[account_status_column] == account_unverified_status_value
|
130
|
+
end
|
131
|
+
|
122
132
|
def remove_verify_account_key
|
123
133
|
verify_account_ds.delete
|
124
134
|
end
|
@@ -139,7 +149,7 @@ module Rodauth
|
|
139
149
|
end
|
140
150
|
|
141
151
|
def new_account(login)
|
142
|
-
if account_from_login(login)
|
152
|
+
if account_from_login(login) && allow_resending_verify_account_email?
|
143
153
|
set_redirect_error_status(unopen_account_error_status)
|
144
154
|
set_error_flash attempt_to_create_unverified_account_notice_message
|
145
155
|
response.write resend_verify_account_view
|
@@ -176,6 +186,14 @@ module Rodauth
|
|
176
186
|
false
|
177
187
|
end
|
178
188
|
|
189
|
+
def login_form_footer
|
190
|
+
super + verify_account_resend_link
|
191
|
+
end
|
192
|
+
|
193
|
+
def verify_account_resend_link
|
194
|
+
"<p><a href=\"#{prefix}/#{verify_account_resend_route}\">Resend Verify Account Information</a></p>"
|
195
|
+
end
|
196
|
+
|
179
197
|
private
|
180
198
|
|
181
199
|
attr_reader :verify_account_key_value
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
module Rodauth
|
4
|
-
|
4
|
+
Feature.define(:verify_account_grace_period, :VerifyAccountGracePeriod) do
|
5
5
|
depends :verify_account
|
6
6
|
error_flash "Cannot change login for unverified account. Please verify this account before changing the login.", "unverified_change_login"
|
7
7
|
redirect :unverified_change_login
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Rodauth
|
4
|
+
Feature.define(:verify_login_change, :VerifyLoginChange) do
|
5
|
+
depends :change_login, :email_base
|
6
|
+
|
7
|
+
error_flash "Unable to verify login change"
|
8
|
+
notice_flash "Your login change has been verified"
|
9
|
+
loaded_templates %w'verify-login-change verify-login-change-email'
|
10
|
+
view 'verify-login-change', 'Verify Login Change'
|
11
|
+
additional_form_tags
|
12
|
+
after
|
13
|
+
before
|
14
|
+
button 'Verify Login Change'
|
15
|
+
redirect
|
16
|
+
|
17
|
+
auth_value_method :no_matching_verify_login_change_key_message, "invalid verify login change key"
|
18
|
+
auth_value_method :verify_login_change_autologin?, false
|
19
|
+
auth_value_method :verify_login_change_deadline_column, :deadline
|
20
|
+
auth_value_method :verify_login_change_deadline_interval, {:days=>1}
|
21
|
+
auth_value_method :verify_login_change_email_subject, 'Verify Login Change'
|
22
|
+
auth_value_method :verify_login_change_id_column, :id
|
23
|
+
auth_value_method :verify_login_change_key_column, :key
|
24
|
+
auth_value_method :verify_login_change_key_param, 'key'
|
25
|
+
auth_value_method :verify_login_change_login_column, :login
|
26
|
+
auth_value_method :verify_login_change_session_key, :verify_login_change_key
|
27
|
+
auth_value_method :verify_login_change_table, :account_login_change_keys
|
28
|
+
|
29
|
+
auth_methods(
|
30
|
+
:create_verify_login_change_email,
|
31
|
+
:create_verify_login_change_key,
|
32
|
+
:get_verify_login_change_login_and_key,
|
33
|
+
:remove_verify_login_change_key,
|
34
|
+
:send_verify_login_change_email,
|
35
|
+
:verify_login_change,
|
36
|
+
:verify_login_change_email_body,
|
37
|
+
:verify_login_change_email_link,
|
38
|
+
:verify_login_change_key_insert_hash,
|
39
|
+
:verify_login_change_key_value,
|
40
|
+
:verify_login_change_new_login,
|
41
|
+
:verify_login_change_old_login
|
42
|
+
)
|
43
|
+
|
44
|
+
auth_private_methods(
|
45
|
+
:account_from_verify_login_change_key
|
46
|
+
)
|
47
|
+
|
48
|
+
route do |r|
|
49
|
+
check_already_logged_in
|
50
|
+
before_verify_login_change_route
|
51
|
+
|
52
|
+
r.get do
|
53
|
+
if key = param_or_nil(verify_login_change_key_param)
|
54
|
+
session[verify_login_change_session_key] = key
|
55
|
+
redirect(r.path)
|
56
|
+
end
|
57
|
+
|
58
|
+
if key = session[verify_login_change_session_key]
|
59
|
+
if account_from_verify_login_change_key(key)
|
60
|
+
verify_login_change_view
|
61
|
+
else
|
62
|
+
session[verify_login_change_session_key] = nil
|
63
|
+
set_redirect_error_flash no_matching_verify_login_change_key_message
|
64
|
+
redirect require_login_redirect
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
r.post do
|
70
|
+
key = session[verify_login_change_session_key] || param(verify_login_change_key_param)
|
71
|
+
unless account_from_verify_login_change_key(key)
|
72
|
+
set_redirect_error_status(invalid_key_error_status)
|
73
|
+
set_redirect_error_flash verify_login_change_error_flash
|
74
|
+
redirect verify_login_change_redirect
|
75
|
+
end
|
76
|
+
|
77
|
+
transaction do
|
78
|
+
before_verify_login_change
|
79
|
+
verify_login_change
|
80
|
+
remove_verify_login_change_key
|
81
|
+
after_verify_login_change
|
82
|
+
end
|
83
|
+
|
84
|
+
if verify_login_change_autologin?
|
85
|
+
update_session
|
86
|
+
end
|
87
|
+
|
88
|
+
session[verify_login_change_session_key] = nil
|
89
|
+
set_notice_flash verify_login_change_notice_flash
|
90
|
+
redirect verify_login_change_redirect
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def remove_verify_login_change_key
|
95
|
+
verify_login_change_ds.delete
|
96
|
+
end
|
97
|
+
|
98
|
+
def verify_login_change
|
99
|
+
update_account(login_column=>verify_login_change_new_login)
|
100
|
+
end
|
101
|
+
|
102
|
+
def account_from_verify_login_change_key(key)
|
103
|
+
@account = _account_from_verify_login_change_key(key)
|
104
|
+
end
|
105
|
+
|
106
|
+
def send_verify_login_change_email(login)
|
107
|
+
create_verify_login_change_email(login).deliver!
|
108
|
+
end
|
109
|
+
|
110
|
+
def verify_login_change_email_link
|
111
|
+
token_link(verify_login_change_route, verify_login_change_key_param, verify_login_change_key_value)
|
112
|
+
end
|
113
|
+
|
114
|
+
def get_verify_login_change_login_and_key(id)
|
115
|
+
verify_login_change_ds(id).get([verify_login_change_login_column, verify_login_change_key_column])
|
116
|
+
end
|
117
|
+
|
118
|
+
def change_login_notice_flash
|
119
|
+
"An email has been sent to you with a link to verify your login change"
|
120
|
+
end
|
121
|
+
|
122
|
+
def verify_login_change_old_login
|
123
|
+
account_ds.get(login_column)
|
124
|
+
end
|
125
|
+
|
126
|
+
attr_reader :verify_login_change_key_value
|
127
|
+
attr_reader :verify_login_change_new_login
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def after_close_account
|
132
|
+
remove_verify_login_change_key
|
133
|
+
super if defined?(super)
|
134
|
+
end
|
135
|
+
|
136
|
+
def update_login(login)
|
137
|
+
generate_verify_login_change_key_value
|
138
|
+
@verify_login_change_new_login = login
|
139
|
+
create_verify_login_change_key(login)
|
140
|
+
send_verify_login_change_email(login)
|
141
|
+
end
|
142
|
+
|
143
|
+
def generate_verify_login_change_key_value
|
144
|
+
@verify_login_change_key_value = random_key
|
145
|
+
end
|
146
|
+
|
147
|
+
def create_verify_login_change_key(login)
|
148
|
+
ds = verify_login_change_ds
|
149
|
+
transaction do
|
150
|
+
ds.where((Sequel::CURRENT_TIMESTAMP > verify_login_change_deadline_column) | ~Sequel.expr(verify_login_change_login_column=>login)).delete
|
151
|
+
if e = raised_uniqueness_violation{ds.insert(verify_login_change_key_insert_hash(login))}
|
152
|
+
old_login, key = get_verify_login_change_login_and_key(account_id)
|
153
|
+
# If inserting into the verify account table causes a violation, we can pull the
|
154
|
+
# key from the verify login change table if the logins match, or reraise.
|
155
|
+
@verify_login_change_key_value = if old_login.downcase == login.downcase
|
156
|
+
key
|
157
|
+
end
|
158
|
+
raise e unless @verify_login_change_key_value
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def verify_login_change_key_insert_hash(login)
|
164
|
+
hash = {verify_login_change_id_column=>account_id, verify_login_change_key_column=>verify_login_change_key_value, verify_login_change_login_column=>login}
|
165
|
+
set_deadline_value(hash, verify_login_change_deadline_column, verify_login_change_deadline_interval)
|
166
|
+
hash
|
167
|
+
end
|
168
|
+
|
169
|
+
def create_verify_login_change_email(login)
|
170
|
+
create_email_to(login, verify_login_change_email_subject, verify_login_change_email_body)
|
171
|
+
end
|
172
|
+
|
173
|
+
def verify_login_change_email_body
|
174
|
+
render('verify-login-change-email')
|
175
|
+
end
|
176
|
+
|
177
|
+
def verify_login_change_ds(id=account_id)
|
178
|
+
db[verify_login_change_table].where(verify_login_change_id_column=>id)
|
179
|
+
end
|
180
|
+
|
181
|
+
def _account_from_verify_login_change_key(token)
|
182
|
+
account_from_key(token) do |id|
|
183
|
+
@verify_login_change_new_login, key = get_verify_login_change_login_and_key(id)
|
184
|
+
key
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
data/lib/rodauth/version.rb
CHANGED
data/lib/rodauth.rb
CHANGED
@@ -20,7 +20,14 @@ module Rodauth
|
|
20
20
|
|
21
21
|
def self.configure(app, opts={}, &block)
|
22
22
|
app.opts[:rodauth_json] = opts.fetch(:json, app.opts[:rodauth_json])
|
23
|
-
(
|
23
|
+
auth_class = (app.opts[:rodauths] ||= {})[opts[:name]] ||= Class.new(Auth)
|
24
|
+
if !auth_class.roda_class
|
25
|
+
auth_class.roda_class = app
|
26
|
+
elsif auth_class.roda_class != app
|
27
|
+
auth_class = app.opts[:rodauths][opts[:name]] = Class.new(auth_class)
|
28
|
+
auth_class.roda_class = app
|
29
|
+
end
|
30
|
+
auth_class.configure(&block)
|
24
31
|
end
|
25
32
|
|
26
33
|
FEATURES = {}
|
@@ -97,7 +104,7 @@ module Rodauth
|
|
97
104
|
routes << handle_meth
|
98
105
|
end
|
99
106
|
|
100
|
-
def self.define(name, &block)
|
107
|
+
def self.define(name, constant=nil, &block)
|
101
108
|
feature = new
|
102
109
|
feature.dependencies = []
|
103
110
|
feature.routes = []
|
@@ -105,6 +112,12 @@ module Rodauth
|
|
105
112
|
configuration = feature.configuration = FeatureConfiguration.new
|
106
113
|
feature.module_eval(&block)
|
107
114
|
configuration.def_configuration_methods(feature)
|
115
|
+
|
116
|
+
if constant
|
117
|
+
Rodauth.const_set(constant, feature)
|
118
|
+
Rodauth::FeatureConfiguration.const_set(constant, configuration)
|
119
|
+
end
|
120
|
+
|
108
121
|
FEATURES[name] = feature
|
109
122
|
end
|
110
123
|
|
@@ -180,6 +193,7 @@ module Rodauth
|
|
180
193
|
|
181
194
|
class Auth
|
182
195
|
class << self
|
196
|
+
attr_accessor :roda_class
|
183
197
|
attr_reader :features
|
184
198
|
attr_reader :routes
|
185
199
|
attr_accessor :route_hash
|
data/spec/migrate/001_tables.rb
CHANGED
@@ -45,6 +45,14 @@ Sequel.migration do
|
|
45
45
|
DateTime :requested_at, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
|
46
46
|
end
|
47
47
|
|
48
|
+
# Used by the verify login change feature
|
49
|
+
create_table(:account_login_change_keys) do
|
50
|
+
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
51
|
+
String :key, :null=>false
|
52
|
+
String :login, :null=>false
|
53
|
+
DateTime :deadline, deadline_opts[1]
|
54
|
+
end
|
55
|
+
|
48
56
|
# Used by the remember me feature
|
49
57
|
create_table(:account_remember_keys) do
|
50
58
|
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
@@ -121,6 +129,7 @@ Sequel.migration do
|
|
121
129
|
run "GRANT ALL ON accounts TO #{user}"
|
122
130
|
run "GRANT ALL ON account_password_reset_keys TO #{user}"
|
123
131
|
run "GRANT ALL ON account_verification_keys TO #{user}"
|
132
|
+
run "GRANT ALL ON account_login_change_keys TO #{user}"
|
124
133
|
run "GRANT ALL ON account_remember_keys TO #{user}"
|
125
134
|
run "GRANT ALL ON account_login_failures TO #{user}"
|
126
135
|
run "GRANT ALL ON account_lockouts TO #{user}"
|
@@ -143,6 +152,7 @@ Sequel.migration do
|
|
143
152
|
:account_lockouts,
|
144
153
|
:account_login_failures,
|
145
154
|
:account_remember_keys,
|
155
|
+
:account_login_change_keys,
|
146
156
|
:account_verification_keys,
|
147
157
|
:account_password_reset_keys,
|
148
158
|
:accounts,
|
@@ -52,6 +52,13 @@ Sequel.migration do
|
|
52
52
|
DateTime :requested_at, :null=>false, :default=>Sequel::CURRENT_TIMESTAMP
|
53
53
|
end
|
54
54
|
|
55
|
+
create_table(:account_login_change_keys) do
|
56
|
+
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
57
|
+
String :key, :null=>false
|
58
|
+
String :login, :null=>false
|
59
|
+
DateTime :deadline, deadline_opts[1]
|
60
|
+
end
|
61
|
+
|
55
62
|
create_table(:account_remember_keys) do
|
56
63
|
foreign_key :id, :accounts, :primary_key=>true, :type=>:Bignum
|
57
64
|
String :key, :null=>false
|