rodauth 2.12.0 → 2.16.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 +30 -0
- data/README.rdoc +50 -7
- data/doc/base.rdoc +1 -0
- data/doc/error_reasons.rdoc +73 -0
- data/doc/internal_request.rdoc +463 -0
- data/doc/path_class_methods.rdoc +10 -0
- data/doc/release_notes/2.13.0.txt +19 -0
- data/doc/release_notes/2.14.0.txt +17 -0
- data/doc/release_notes/2.15.0.txt +48 -0
- data/doc/release_notes/2.16.0.txt +20 -0
- data/doc/remember.rdoc +1 -0
- data/lib/rodauth/features/active_sessions.rb +1 -1
- data/lib/rodauth/features/base.rb +26 -1
- data/lib/rodauth/features/change_login.rb +6 -4
- data/lib/rodauth/features/change_password.rb +5 -3
- data/lib/rodauth/features/close_account.rb +3 -1
- data/lib/rodauth/features/confirm_password.rb +2 -2
- data/lib/rodauth/features/create_account.rb +6 -4
- data/lib/rodauth/features/disallow_common_passwords.rb +1 -1
- data/lib/rodauth/features/disallow_password_reuse.rb +1 -1
- data/lib/rodauth/features/email_auth.rb +6 -0
- data/lib/rodauth/features/internal_request.rb +371 -0
- data/lib/rodauth/features/jwt_refresh.rb +1 -1
- data/lib/rodauth/features/lockout.rb +15 -4
- data/lib/rodauth/features/login.rb +6 -3
- data/lib/rodauth/features/login_password_requirements_base.rb +15 -6
- data/lib/rodauth/features/otp.rb +13 -6
- data/lib/rodauth/features/password_complexity.rb +4 -4
- data/lib/rodauth/features/path_class_methods.rb +22 -0
- data/lib/rodauth/features/recovery_codes.rb +6 -2
- data/lib/rodauth/features/remember.rb +25 -10
- data/lib/rodauth/features/reset_password.rb +8 -4
- data/lib/rodauth/features/session_expiration.rb +1 -0
- data/lib/rodauth/features/single_session.rb +1 -0
- data/lib/rodauth/features/sms_codes.rb +17 -5
- data/lib/rodauth/features/two_factor_base.rb +6 -1
- data/lib/rodauth/features/verify_account.rb +8 -1
- data/lib/rodauth/features/verify_account_grace_period.rb +1 -1
- data/lib/rodauth/features/verify_login_change.rb +5 -2
- data/lib/rodauth/features/webauthn.rb +15 -14
- data/lib/rodauth/features/webauthn_login.rb +1 -1
- data/lib/rodauth/version.rb +1 -1
- data/lib/rodauth.rb +20 -2
- data/templates/button.str +1 -1
- data/templates/change-password.str +2 -2
- data/templates/global-logout-field.str +1 -1
- data/templates/login-confirm-field.str +2 -2
- data/templates/login-display.str +2 -2
- data/templates/login-field.str +2 -2
- data/templates/otp-auth-code-field.str +2 -2
- data/templates/otp-setup.str +2 -2
- data/templates/password-confirm-field.str +2 -2
- data/templates/password-field.str +2 -2
- data/templates/recovery-auth.str +2 -2
- data/templates/remember.str +1 -1
- data/templates/sms-code-field.str +2 -2
- data/templates/sms-setup.str +2 -2
- data/templates/webauthn-remove.str +1 -1
- metadata +19 -3
@@ -135,7 +135,7 @@ module Rodauth
|
|
135
135
|
end
|
136
136
|
|
137
137
|
def _jwt_decode_opts
|
138
|
-
if allow_refresh_with_expired_jwt_access_token? && @jwt_refresh_route
|
138
|
+
if allow_refresh_with_expired_jwt_access_token? && (@jwt_refresh_route || request.path == jwt_refresh_path)
|
139
139
|
Hash[super].merge!(:verify_expiration=>false)
|
140
140
|
else
|
141
141
|
super
|
@@ -62,6 +62,10 @@ module Rodauth
|
|
62
62
|
)
|
63
63
|
auth_private_methods :account_from_unlock_key
|
64
64
|
|
65
|
+
internal_request_method(:lock_account)
|
66
|
+
internal_request_method(:unlock_account_request)
|
67
|
+
internal_request_method(:unlock_account)
|
68
|
+
|
65
69
|
route(:unlock_account_request) do |r|
|
66
70
|
check_already_logged_in
|
67
71
|
before_unlock_account_request_route
|
@@ -84,6 +88,7 @@ module Rodauth
|
|
84
88
|
set_notice_flash unlock_account_request_notice_flash
|
85
89
|
else
|
86
90
|
set_redirect_error_status(no_matching_login_error_status)
|
91
|
+
set_error_reason :no_matching_login
|
87
92
|
set_redirect_error_flash no_matching_login_message.to_s.capitalize
|
88
93
|
end
|
89
94
|
|
@@ -116,6 +121,7 @@ module Rodauth
|
|
116
121
|
key = session[unlock_account_session_key] || param(unlock_account_key_param)
|
117
122
|
unless account_from_unlock_key(key)
|
118
123
|
set_redirect_error_status invalid_key_error_status
|
124
|
+
set_error_reason :invalid_unlock_account_key
|
119
125
|
set_redirect_error_flash no_matching_unlock_account_key_error_flash
|
120
126
|
redirect unlock_account_request_redirect
|
121
127
|
end
|
@@ -134,7 +140,7 @@ module Rodauth
|
|
134
140
|
set_notice_flash unlock_account_notice_flash
|
135
141
|
redirect unlock_account_redirect
|
136
142
|
else
|
137
|
-
|
143
|
+
set_response_error_reason_status(:invalid_password, invalid_password_error_status)
|
138
144
|
set_field_error(password_param, invalid_password_message)
|
139
145
|
set_error_flash unlock_account_error_flash
|
140
146
|
unlock_account_view
|
@@ -165,6 +171,12 @@ module Rodauth
|
|
165
171
|
unlock_account
|
166
172
|
end
|
167
173
|
|
174
|
+
def _setup_account_lockouts_hash(account_id, key)
|
175
|
+
hash = {account_lockouts_id_column=>account_id, account_lockouts_key_column=>key}
|
176
|
+
set_deadline_value(hash, account_lockouts_deadline_column, account_lockouts_deadline_interval)
|
177
|
+
hash
|
178
|
+
end
|
179
|
+
|
168
180
|
def invalid_login_attempted
|
169
181
|
ds = account_login_failures_ds.
|
170
182
|
where(account_login_failures_id_column=>account_id)
|
@@ -190,8 +202,7 @@ module Rodauth
|
|
190
202
|
|
191
203
|
if number >= max_invalid_logins
|
192
204
|
@unlock_account_key_value = generate_unlock_account_key
|
193
|
-
hash =
|
194
|
-
set_deadline_value(hash, account_lockouts_deadline_column, account_lockouts_deadline_interval)
|
205
|
+
hash = _setup_account_lockouts_hash(account_id, unlock_account_key_value)
|
195
206
|
|
196
207
|
if e = raised_uniqueness_violation{account_lockouts_ds.insert(hash)}
|
197
208
|
# If inserting into the lockout table raises a violation, we should just be able to pull the already inserted
|
@@ -271,7 +282,7 @@ module Rodauth
|
|
271
282
|
end
|
272
283
|
|
273
284
|
def show_lockout_page
|
274
|
-
|
285
|
+
set_response_error_reason_status(:account_locked_out, lockout_error_status)
|
275
286
|
set_error_flash login_lockout_error_flash
|
276
287
|
response.write unlock_account_request_view
|
277
288
|
request.halt
|
@@ -25,6 +25,9 @@ module Rodauth
|
|
25
25
|
|
26
26
|
auth_value_methods :login_return_to_requested_location_path
|
27
27
|
|
28
|
+
internal_request_method
|
29
|
+
internal_request_method :valid_login_and_password?
|
30
|
+
|
28
31
|
route do |r|
|
29
32
|
check_already_logged_in
|
30
33
|
before_login_route
|
@@ -39,13 +42,13 @@ module Rodauth
|
|
39
42
|
|
40
43
|
catch_error do
|
41
44
|
unless account_from_login(param(login_param))
|
42
|
-
|
45
|
+
throw_error_reason(:no_matching_login, no_matching_login_error_status, login_param, no_matching_login_message)
|
43
46
|
end
|
44
47
|
|
45
48
|
before_login_attempt
|
46
49
|
|
47
50
|
unless open_account?
|
48
|
-
|
51
|
+
throw_error_reason(:unverified_account, unopen_account_error_status, login_param, unverified_account_message)
|
49
52
|
end
|
50
53
|
|
51
54
|
if use_multi_phase_login?
|
@@ -61,7 +64,7 @@ module Rodauth
|
|
61
64
|
|
62
65
|
unless password_match?(param(password_param))
|
63
66
|
after_login_failure
|
64
|
-
|
67
|
+
throw_error_reason(:invalid_password, login_error_status, password_param, invalid_password_message)
|
65
68
|
end
|
66
69
|
|
67
70
|
login('password')
|
@@ -81,6 +81,11 @@ module Rodauth
|
|
81
81
|
def password_too_short_message
|
82
82
|
"minimum #{password_minimum_length} characters"
|
83
83
|
end
|
84
|
+
|
85
|
+
def set_password_requirement_error_message(reason, message)
|
86
|
+
set_error_reason(reason)
|
87
|
+
@password_requirement_message = message
|
88
|
+
end
|
84
89
|
|
85
90
|
def login_does_not_meet_requirements_message
|
86
91
|
"invalid login#{", #{login_requirement_message}" if login_requirement_message}"
|
@@ -93,13 +98,18 @@ module Rodauth
|
|
93
98
|
def login_too_short_message
|
94
99
|
"minimum #{login_minimum_length} characters"
|
95
100
|
end
|
101
|
+
|
102
|
+
def set_login_requirement_error_message(reason, message)
|
103
|
+
set_error_reason(reason)
|
104
|
+
@login_requirement_message = message
|
105
|
+
end
|
96
106
|
|
97
107
|
def login_meets_length_requirements?(login)
|
98
108
|
if login_minimum_length > login.length
|
99
|
-
|
109
|
+
set_login_requirement_error_message(:login_too_short, login_too_short_message)
|
100
110
|
false
|
101
111
|
elsif login_maximum_length < login.length
|
102
|
-
|
112
|
+
set_login_requirement_error_message(:login_too_long, login_too_long_message)
|
103
113
|
false
|
104
114
|
else
|
105
115
|
true
|
@@ -109,7 +119,7 @@ module Rodauth
|
|
109
119
|
def login_meets_email_requirements?(login)
|
110
120
|
return true unless require_email_address_logins?
|
111
121
|
return true if login_valid_email?(login)
|
112
|
-
|
122
|
+
set_login_requirement_error_message(:login_not_valid_email, login_not_valid_email_message)
|
113
123
|
return false
|
114
124
|
end
|
115
125
|
|
@@ -119,13 +129,13 @@ module Rodauth
|
|
119
129
|
|
120
130
|
def password_meets_length_requirements?(password)
|
121
131
|
return true if password_minimum_length <= password.length
|
122
|
-
|
132
|
+
set_password_requirement_error_message(:password_too_short, password_too_short_message)
|
123
133
|
false
|
124
134
|
end
|
125
135
|
|
126
136
|
def password_does_not_contain_null_byte?(password)
|
127
137
|
return true unless password.include?("\0")
|
128
|
-
|
138
|
+
set_password_requirement_error_message(:password_contains_null_byte, contains_null_byte_message)
|
129
139
|
false
|
130
140
|
end
|
131
141
|
|
@@ -150,4 +160,3 @@ module Rodauth
|
|
150
160
|
end
|
151
161
|
end
|
152
162
|
end
|
153
|
-
|
data/lib/rodauth/features/otp.rb
CHANGED
@@ -96,6 +96,12 @@ module Rodauth
|
|
96
96
|
:otp_tmp_key
|
97
97
|
)
|
98
98
|
|
99
|
+
internal_request_method :otp_setup_params
|
100
|
+
internal_request_method :otp_setup
|
101
|
+
internal_request_method :otp_auth
|
102
|
+
internal_request_method :valid_otp_auth?
|
103
|
+
internal_request_method :otp_disable
|
104
|
+
|
99
105
|
route(:otp_auth) do |r|
|
100
106
|
require_login
|
101
107
|
require_account_session
|
@@ -103,7 +109,7 @@ module Rodauth
|
|
103
109
|
require_otp_setup
|
104
110
|
|
105
111
|
if otp_locked_out?
|
106
|
-
|
112
|
+
set_response_error_reason_status(:otp_locked_out, lockout_error_status)
|
107
113
|
set_redirect_error_flash otp_lockout_error_flash
|
108
114
|
redirect otp_lockout_redirect
|
109
115
|
end
|
@@ -122,7 +128,7 @@ module Rodauth
|
|
122
128
|
|
123
129
|
otp_record_authentication_failure
|
124
130
|
after_otp_authentication_failure
|
125
|
-
|
131
|
+
set_response_error_reason_status(:invalid_otp_auth_code, invalid_key_error_status)
|
126
132
|
set_field_error(otp_auth_param, otp_invalid_auth_code_message)
|
127
133
|
set_error_flash otp_auth_error_flash
|
128
134
|
otp_auth_view
|
@@ -149,7 +155,7 @@ module Rodauth
|
|
149
155
|
catch_error do
|
150
156
|
unless otp_valid_key?(secret)
|
151
157
|
otp_tmp_key(otp_new_secret)
|
152
|
-
|
158
|
+
throw_error_reason(:invalid_otp_secret, invalid_field_error_status, otp_setup_param, otp_invalid_secret_message)
|
153
159
|
end
|
154
160
|
|
155
161
|
if otp_keys_use_hmac?
|
@@ -159,11 +165,11 @@ module Rodauth
|
|
159
165
|
end
|
160
166
|
|
161
167
|
unless two_factor_password_match?(param(password_param))
|
162
|
-
|
168
|
+
throw_error_reason(:invalid_password, invalid_password_error_status, password_param, invalid_password_message)
|
163
169
|
end
|
164
170
|
|
165
171
|
unless otp_valid_code?(param(otp_auth_param))
|
166
|
-
|
172
|
+
throw_error_reason(:invalid_otp_auth_code, invalid_key_error_status, otp_auth_param, otp_invalid_auth_code_message)
|
167
173
|
end
|
168
174
|
|
169
175
|
transaction do
|
@@ -206,7 +212,7 @@ module Rodauth
|
|
206
212
|
redirect otp_disable_redirect
|
207
213
|
end
|
208
214
|
|
209
|
-
|
215
|
+
set_response_error_reason_status(:invalid_password, invalid_password_error_status)
|
210
216
|
set_field_error(password_param, invalid_password_message)
|
211
217
|
set_error_flash otp_disable_error_flash
|
212
218
|
otp_disable_view
|
@@ -226,6 +232,7 @@ module Rodauth
|
|
226
232
|
def require_otp_setup
|
227
233
|
unless otp_exists?
|
228
234
|
set_redirect_error_status(two_factor_not_setup_error_status)
|
235
|
+
set_error_reason :two_factor_not_setup
|
229
236
|
set_redirect_error_flash two_factor_not_setup_error_flash
|
230
237
|
redirect two_factor_need_setup_redirect
|
231
238
|
end
|
@@ -54,21 +54,21 @@ module Rodauth
|
|
54
54
|
def password_has_enough_character_groups?(password)
|
55
55
|
return true if password.length > password_max_length_for_groups_check
|
56
56
|
return true if password_character_groups.select{|re| password =~ re}.length >= password_min_groups
|
57
|
-
|
57
|
+
set_password_requirement_error_message(:not_enough_character_groups_in_password, password_not_enough_character_groups_message)
|
58
58
|
false
|
59
59
|
end
|
60
60
|
|
61
61
|
def password_has_no_invalid_pattern?(password)
|
62
62
|
return true unless password_invalid_pattern
|
63
63
|
return true if password !~ password_invalid_pattern
|
64
|
-
|
64
|
+
set_password_requirement_error_message(:invalid_password_pattern, password_invalid_pattern_message)
|
65
65
|
false
|
66
66
|
end
|
67
67
|
|
68
68
|
def password_not_too_many_repeating_characters?(password)
|
69
69
|
return true if password_max_repeating_characters < 2
|
70
70
|
return true if password !~ /(.)(\1){#{password_max_repeating_characters-1}}/
|
71
|
-
|
71
|
+
set_password_requirement_error_message(:too_many_repeating_characters_in_password, password_too_many_repeating_characters_message)
|
72
72
|
false
|
73
73
|
end
|
74
74
|
|
@@ -77,7 +77,7 @@ module Rodauth
|
|
77
77
|
return true unless password =~ /\A(?:\d*)([A-Za-z!@$+|][A-Za-z!@$+|0134578]+[A-Za-z!@$+|])(?:\d*)\z/
|
78
78
|
word = $1.downcase.tr('!@$+|0134578', 'iastloleastb')
|
79
79
|
return true if !dict.include?(word)
|
80
|
-
|
80
|
+
set_password_requirement_error_message(:password_in_dictionary, password_in_dictionary_message)
|
81
81
|
false
|
82
82
|
end
|
83
83
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Rodauth
|
4
|
+
Feature.define(:path_class_methods, :PathClassMethods) do
|
5
|
+
def post_configure
|
6
|
+
super
|
7
|
+
|
8
|
+
klass = self.class
|
9
|
+
klass.features.each do |feature_name|
|
10
|
+
feature = FEATURES[feature_name]
|
11
|
+
feature.routes.each do |handle_meth|
|
12
|
+
route = handle_meth.to_s.sub(/\Ahandle_/, '')
|
13
|
+
path_meth = :"#{route}_path"
|
14
|
+
url_meth = :"#{route}_url"
|
15
|
+
instance = klass.allocate.freeze
|
16
|
+
klass.define_singleton_method(path_meth){|opts={}| instance.send(path_meth, opts)}
|
17
|
+
klass.define_singleton_method(url_meth){|opts={}| instance.send(url_meth, opts)}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -59,6 +59,10 @@ module Rodauth
|
|
59
59
|
:recovery_code_match?,
|
60
60
|
)
|
61
61
|
|
62
|
+
internal_request_method :recovery_codes
|
63
|
+
internal_request_method :recovery_auth
|
64
|
+
internal_request_method :valid_recovery_auth?
|
65
|
+
|
62
66
|
route(:recovery_auth) do |r|
|
63
67
|
require_login
|
64
68
|
require_account_session
|
@@ -76,7 +80,7 @@ module Rodauth
|
|
76
80
|
two_factor_authenticate('recovery_code')
|
77
81
|
end
|
78
82
|
|
79
|
-
|
83
|
+
set_response_error_reason_status(:invalid_recovery_code, invalid_key_error_status)
|
80
84
|
set_field_error(recovery_codes_param, invalid_recovery_code_message)
|
81
85
|
set_error_flash invalid_recovery_code_error_flash
|
82
86
|
recovery_auth_view
|
@@ -119,7 +123,7 @@ module Rodauth
|
|
119
123
|
set_error_flash view_recovery_codes_error_flash
|
120
124
|
end
|
121
125
|
|
122
|
-
|
126
|
+
set_response_error_reason_status(:invalid_password, invalid_password_error_status)
|
123
127
|
set_field_error(password_param, invalid_password_message)
|
124
128
|
recovery_codes_view
|
125
129
|
end
|
@@ -39,12 +39,17 @@ module Rodauth
|
|
39
39
|
:generate_remember_key_value,
|
40
40
|
:get_remember_key,
|
41
41
|
:load_memory,
|
42
|
+
:remembered_session_id,
|
42
43
|
:logged_in_via_remember_key?,
|
43
44
|
:remember_key_value,
|
44
45
|
:remember_login,
|
45
46
|
:remove_remember_key
|
46
47
|
)
|
47
48
|
|
49
|
+
internal_request_method :remember_setup
|
50
|
+
internal_request_method :remember_disable
|
51
|
+
internal_request_method :account_id_for_remember_key
|
52
|
+
|
48
53
|
route do |r|
|
49
54
|
require_account
|
50
55
|
before_remember_route
|
@@ -74,36 +79,42 @@ module Rodauth
|
|
74
79
|
set_notice_flash remember_notice_flash
|
75
80
|
redirect remember_redirect
|
76
81
|
else
|
77
|
-
|
82
|
+
set_response_error_reason_status(:invalid_remember_param, invalid_field_error_status)
|
78
83
|
set_error_flash remember_error_flash
|
79
84
|
remember_view
|
80
85
|
end
|
81
86
|
end
|
82
87
|
end
|
83
88
|
|
84
|
-
def
|
85
|
-
return
|
86
|
-
return unless cookie = request.cookies[remember_cookie_key]
|
89
|
+
def remembered_session_id
|
90
|
+
return unless cookie = _get_remember_cookie
|
87
91
|
id, key = cookie.split('_', 2)
|
88
92
|
return unless id && key
|
89
93
|
|
90
94
|
actual, deadline = active_remember_key_ds(id).get([remember_key_column, remember_deadline_column])
|
91
|
-
unless actual
|
92
|
-
forget_login
|
93
|
-
return
|
94
|
-
end
|
95
|
+
return unless actual
|
95
96
|
|
96
97
|
if hmac_secret
|
97
98
|
unless valid = timing_safe_eql?(key, compute_hmac(actual))
|
98
99
|
unless raw_remember_token_deadline && raw_remember_token_deadline > convert_timestamp(deadline)
|
99
|
-
forget_login
|
100
100
|
return
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
105
|
unless valid || timing_safe_eql?(key, actual)
|
106
|
-
|
106
|
+
return
|
107
|
+
end
|
108
|
+
|
109
|
+
id
|
110
|
+
end
|
111
|
+
|
112
|
+
def load_memory
|
113
|
+
return if session[session_key]
|
114
|
+
|
115
|
+
unless id = remembered_session_id
|
116
|
+
# Only set expired cookie if there is already a cookie set.
|
117
|
+
forget_login if _get_remember_cookie
|
107
118
|
return
|
108
119
|
end
|
109
120
|
|
@@ -180,6 +191,10 @@ module Rodauth
|
|
180
191
|
|
181
192
|
private
|
182
193
|
|
194
|
+
def _get_remember_cookie
|
195
|
+
request.cookies[remember_cookie_key]
|
196
|
+
end
|
197
|
+
|
183
198
|
def after_logout
|
184
199
|
forget_login
|
185
200
|
super if defined?(super)
|
@@ -57,6 +57,9 @@ module Rodauth
|
|
57
57
|
:account_from_reset_password_key
|
58
58
|
)
|
59
59
|
|
60
|
+
internal_request_method(:reset_password_request)
|
61
|
+
internal_request_method
|
62
|
+
|
60
63
|
route(:reset_password_request) do |r|
|
61
64
|
check_already_logged_in
|
62
65
|
before_reset_password_request_route
|
@@ -68,11 +71,11 @@ module Rodauth
|
|
68
71
|
r.post do
|
69
72
|
catch_error do
|
70
73
|
unless account_from_login(param(login_param))
|
71
|
-
|
74
|
+
throw_error_reason(:no_matching_login, no_matching_login_error_status, login_param, no_matching_login_message)
|
72
75
|
end
|
73
76
|
|
74
77
|
unless open_account?
|
75
|
-
|
78
|
+
throw_error_reason(:unverified_account, unopen_account_error_status, login_param, unverified_account_message)
|
76
79
|
end
|
77
80
|
|
78
81
|
if reset_password_email_recently_sent?
|
@@ -123,6 +126,7 @@ module Rodauth
|
|
123
126
|
key = session[reset_password_session_key] || param(reset_password_key_param)
|
124
127
|
unless account_from_reset_password_key(key)
|
125
128
|
set_redirect_error_status(invalid_key_error_status)
|
129
|
+
set_error_reason :invalid_reset_password_key
|
126
130
|
set_redirect_error_flash reset_password_error_flash
|
127
131
|
redirect reset_password_email_sent_redirect
|
128
132
|
end
|
@@ -130,11 +134,11 @@ module Rodauth
|
|
130
134
|
password = param(password_param)
|
131
135
|
catch_error do
|
132
136
|
if password_match?(password)
|
133
|
-
|
137
|
+
throw_error_reason(:same_as_existing_password, invalid_field_error_status, password_param, same_as_existing_password_message)
|
134
138
|
end
|
135
139
|
|
136
140
|
if require_password_confirmation? && password != param(password_confirm_param)
|
137
|
-
|
141
|
+
throw_error_reason(:passwords_do_not_match, unmatched_field_error_status, password_param, passwords_do_not_match_message)
|
138
142
|
end
|
139
143
|
|
140
144
|
unless password_meets_requirements?(password)
|