clearance 1.10.1 → 1.17.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of clearance might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +20 -8
- data/.yardopts +3 -0
- data/Appraisals +13 -16
- data/Gemfile +7 -5
- data/Gemfile.lock +124 -130
- data/NEWS.md +171 -2
- data/README.md +99 -42
- data/app/controllers/clearance/passwords_controller.rb +35 -21
- data/app/controllers/clearance/sessions_controller.rb +17 -3
- data/app/controllers/clearance/users_controller.rb +10 -4
- data/app/mailers/clearance_mailer.rb +2 -3
- data/app/views/clearance_mailer/change_password.text.erb +1 -1
- data/app/views/layouts/application.html.erb +0 -1
- data/bin/setup +6 -2
- data/clearance.gemspec +5 -2
- data/config/locales/clearance.en.yml +9 -0
- data/gemfiles/rails_4.2.gemfile +20 -0
- data/gemfiles/rails_5.0.gemfile +21 -0
- data/gemfiles/rails_5.1.gemfile +21 -0
- data/gemfiles/rails_5.2.gemfile +21 -0
- data/lib/clearance/authentication.rb +63 -3
- data/lib/clearance/authorization.rb +48 -5
- data/lib/clearance/back_door.rb +55 -6
- data/lib/clearance/configuration.rb +50 -10
- data/lib/clearance/constraints/signed_in.rb +21 -0
- data/lib/clearance/constraints/signed_out.rb +12 -0
- data/lib/clearance/constraints.rb +12 -0
- data/lib/clearance/controller.rb +13 -0
- data/lib/clearance/default_sign_in_guard.rb +17 -0
- data/lib/clearance/engine.rb +18 -5
- data/lib/clearance/password_strategies/bcrypt.rb +16 -21
- data/lib/clearance/password_strategies/bcrypt_migration_from_sha1.rb +10 -0
- data/lib/clearance/password_strategies/blowfish.rb +10 -1
- data/lib/clearance/password_strategies/sha1.rb +9 -0
- data/lib/clearance/password_strategies.rb +13 -0
- data/lib/clearance/rack_session.rb +13 -0
- data/lib/clearance/rspec.rb +15 -4
- data/lib/clearance/session.rb +62 -13
- data/lib/clearance/session_status.rb +7 -0
- data/lib/clearance/sign_in_guard.rb +65 -0
- data/lib/clearance/test_unit.rb +3 -3
- data/lib/clearance/testing/controller_helpers.rb +57 -0
- data/lib/clearance/testing/deny_access_matcher.rb +36 -2
- data/lib/clearance/testing/helpers.rb +9 -25
- data/lib/clearance/testing/view_helpers.rb +32 -0
- data/lib/clearance/token.rb +7 -0
- data/lib/clearance/user.rb +183 -4
- data/lib/clearance/version.rb +1 -1
- data/lib/generators/clearance/install/install_generator.rb +28 -9
- data/lib/generators/clearance/install/templates/README +1 -1
- data/lib/generators/clearance/install/templates/clearance.rb +1 -0
- data/lib/generators/clearance/install/templates/db/migrate/{add_clearance_to_users.rb → add_clearance_to_users.rb.erb} +3 -3
- data/lib/generators/clearance/install/templates/db/migrate/{create_users.rb → create_users.rb.erb} +2 -2
- data/lib/generators/clearance/install/templates/user.rb.erb +3 -0
- data/lib/generators/clearance/routes/routes_generator.rb +23 -0
- data/lib/generators/clearance/routes/templates/routes.rb +7 -7
- data/lib/generators/clearance/specs/templates/factories/clearance.rb +2 -2
- data/lib/generators/clearance/specs/templates/features/clearance/user_signs_out_spec.rb.tt +1 -1
- data/lib/generators/clearance/specs/templates/features/clearance/visitor_resets_password_spec.rb.tt +12 -3
- data/lib/generators/clearance/specs/templates/features/clearance/visitor_signs_in_spec.rb.tt +3 -3
- data/lib/generators/clearance/specs/templates/features/clearance/visitor_signs_up_spec.rb.tt +1 -1
- data/lib/generators/clearance/specs/templates/features/clearance/visitor_updates_password_spec.rb.tt +2 -2
- data/lib/generators/clearance/specs/templates/support/features/clearance_helpers.rb +2 -2
- data/spec/acceptance/clearance_installation_spec.rb +15 -7
- data/spec/app_templates/app/models/rails5/user.rb +5 -0
- data/spec/app_templates/config/initializers/clearance.rb +2 -0
- data/spec/app_templates/testapp/Gemfile +1 -1
- data/spec/app_templates/testapp/app/controllers/home_controller.rb +5 -1
- data/spec/clearance/back_door_spec.rb +70 -6
- data/spec/clearance/session_spec.rb +4 -16
- data/spec/clearance/testing/controller_helpers_spec.rb +38 -0
- data/spec/clearance/testing/view_helpers_spec.rb +37 -0
- data/spec/configuration_spec.rb +79 -86
- data/spec/controllers/apis_controller_spec.rb +6 -2
- data/spec/controllers/forgeries_controller_spec.rb +12 -3
- data/spec/controllers/passwords_controller_spec.rb +74 -38
- data/spec/controllers/permissions_controller_spec.rb +13 -3
- data/spec/controllers/sessions_controller_spec.rb +40 -11
- data/spec/controllers/users_controller_spec.rb +16 -8
- data/spec/dummy/app/controllers/application_controller.rb +5 -1
- data/spec/dummy/application.rb +9 -11
- data/spec/factories.rb +5 -5
- data/spec/generators/clearance/install/install_generator_spec.rb +29 -3
- data/spec/generators/clearance/routes/routes_generator_spec.rb +5 -1
- data/spec/helpers/helper_helpers_spec.rb +10 -0
- data/spec/{user_spec.rb → models/user_spec.rb} +10 -1
- data/spec/password_strategies/blowfish_spec.rb +1 -1
- data/spec/requests/cookie_options_spec.rb +52 -0
- data/spec/requests/csrf_rotation_spec.rb +35 -0
- data/spec/requests/password_maintenance_spec.rb +18 -0
- data/spec/requests/token_expiration_spec.rb +54 -0
- data/spec/spec_helper.rb +22 -4
- data/spec/support/environment.rb +12 -0
- data/spec/support/generator_spec_helpers.rb +13 -1
- data/spec/support/http_method_shim.rb +25 -0
- data/spec/support/request_with_remember_token.rb +5 -0
- data/spec/views/view_helpers_spec.rb +10 -0
- metadata +69 -15
- data/gemfiles/rails3.2.gemfile +0 -18
- data/gemfiles/rails4.0.gemfile +0 -19
- data/gemfiles/rails4.1.gemfile +0 -18
- data/gemfiles/rails4.2.gemfile +0 -18
- data/lib/generators/clearance/install/templates/user.rb +0 -3
- data/spec/clearance/testing/helpers_spec.rb +0 -38
@@ -1,31 +1,15 @@
|
|
1
|
+
require "clerance/testing/controller_helpers"
|
2
|
+
|
1
3
|
module Clearance
|
2
4
|
module Testing
|
5
|
+
# @deprecated Use Clearance::Testing::ControllerHelpers
|
3
6
|
module Helpers
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
unless defined?(FactoryGirl)
|
11
|
-
raise(
|
12
|
-
RuntimeError,
|
13
|
-
"Clearance's `sign_in` helper requires factory_girl"
|
14
|
-
)
|
15
|
-
end
|
16
|
-
|
17
|
-
factory = Clearance.configuration.user_model.to_s.underscore.to_sym
|
18
|
-
sign_in_as FactoryGirl.create(factory)
|
19
|
-
end
|
20
|
-
|
21
|
-
def sign_in_as(user)
|
22
|
-
@controller.sign_in user
|
23
|
-
user
|
24
|
-
end
|
25
|
-
|
26
|
-
def sign_out
|
27
|
-
@controller.sign_out
|
28
|
-
end
|
7
|
+
warn(
|
8
|
+
"#{Kernel.caller.first} [DEPRECATION] Clearance::Testing::Helpers is "\
|
9
|
+
"deprecated and has been replaced with " \
|
10
|
+
"Clearance::Testing::ControllerHelpers. Require " \
|
11
|
+
"clearance/testing/controller_helpers instead."
|
12
|
+
)
|
29
13
|
end
|
30
14
|
end
|
31
15
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Clearance
|
2
|
+
module Testing
|
3
|
+
# Provides helpers to your view and helper specs.
|
4
|
+
# Using these helpers makes `current_user`, `signed_in?` and `signed_out?`
|
5
|
+
# behave properly in view and helper specs.
|
6
|
+
module ViewHelpers
|
7
|
+
# Sets current_user on the view under test to a new instance of your user
|
8
|
+
# model.
|
9
|
+
def sign_in
|
10
|
+
view.current_user = Clearance.configuration.user_model.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# Sets current_user on the view under test to the supplied user.
|
14
|
+
def sign_in_as(user)
|
15
|
+
view.current_user = user
|
16
|
+
end
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
module CurrentUser
|
20
|
+
attr_accessor :current_user
|
21
|
+
|
22
|
+
def signed_in?
|
23
|
+
current_user.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def signed_out?
|
27
|
+
!signed_in?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/clearance/token.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
module Clearance
|
2
|
+
# Random token used for password reset and remember tokens.
|
3
|
+
# Clearance tokens are also public API and are inteded to be used anywhere you
|
4
|
+
# need a random token to correspond to a given user (e.g. you added an email
|
5
|
+
# confirmation token).
|
2
6
|
class Token
|
7
|
+
# Generate a new random, 20 byte hex token.
|
8
|
+
#
|
9
|
+
# @return [String]
|
3
10
|
def self.new
|
4
11
|
SecureRandom.hex(20).encode('UTF-8')
|
5
12
|
end
|
data/lib/clearance/user.rb
CHANGED
@@ -1,25 +1,142 @@
|
|
1
1
|
require 'digest/sha1'
|
2
|
+
require 'active_model'
|
2
3
|
require 'email_validator'
|
3
4
|
require 'clearance/token'
|
4
5
|
|
5
6
|
module Clearance
|
7
|
+
# Required to be included in your configued user class, which is `User` by
|
8
|
+
# default, but can be changed with {Configuration#user_model=}.
|
9
|
+
#
|
10
|
+
# class User
|
11
|
+
# include Clearance::User
|
12
|
+
#
|
13
|
+
# # ...
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# This will also include methods exposed by your password strategy, which can
|
17
|
+
# be configured with {Configuration#password_strategy=}. By default, this is
|
18
|
+
# {PasswordStrategies::BCrypt}.
|
19
|
+
#
|
20
|
+
# ## Validations
|
21
|
+
#
|
22
|
+
# These validations are added to the class that the {User} module is mixed
|
23
|
+
# into.
|
24
|
+
#
|
25
|
+
# * If {#email_optional?} is false, {#email} is validated for presence,
|
26
|
+
# uniqueness and email format (using the `email_validator` gem in strict
|
27
|
+
# mode).
|
28
|
+
# * If {#skip_password_validation?} is false, {#password} is validated
|
29
|
+
# for presence.
|
30
|
+
#
|
31
|
+
# ## Callbacks
|
32
|
+
#
|
33
|
+
# * {#normalize_email} will be called on `before_validation`
|
34
|
+
# * {#generate_remember_token} will be called on `before_create`
|
35
|
+
#
|
36
|
+
# @!attribute email
|
37
|
+
# @return [String] The user's email.
|
38
|
+
#
|
39
|
+
# @!attribute encrypted_password
|
40
|
+
# @return [String] The user's encrypted password.
|
41
|
+
#
|
42
|
+
# @!attribute remember_token
|
43
|
+
# @return [String] The value used to identify this user in their {Session}
|
44
|
+
# cookie.
|
45
|
+
#
|
46
|
+
# @!attribute confirmation_token
|
47
|
+
# @return [String] The value used to identify this user in the password
|
48
|
+
# reset link.
|
49
|
+
#
|
50
|
+
# @!attribute password_changing
|
51
|
+
# @deprecated Dirty tracking is now handled automatically.
|
52
|
+
#
|
53
|
+
# @!attribute [r] password
|
54
|
+
# @return [String] Transient (non-persisted) attribute that is set when
|
55
|
+
# updating a user's password. Only the {#encrypted_password} is persisted.
|
56
|
+
#
|
57
|
+
# @!method password=
|
58
|
+
# Sets the user's encrypted_password by using the configured Password
|
59
|
+
# Strategy's `password=` method. By default, this will be
|
60
|
+
# {PasswordStrategies::BCrypt#password=}, but can be changed with
|
61
|
+
# {Configuration#password_strategy}.
|
62
|
+
#
|
63
|
+
# @see PasswordStrategies
|
64
|
+
# @return [void]
|
65
|
+
#
|
66
|
+
# @!method authenticated?
|
67
|
+
# Check's the provided password against the user's encrypted password using
|
68
|
+
# the configured password strategy. By default, this will be
|
69
|
+
# {PasswordStrategies::BCrypt#authenticated?}, but can be changed with
|
70
|
+
# {Configuration#password_strategy}.
|
71
|
+
#
|
72
|
+
# @see PasswordStrategies
|
73
|
+
# @param [String] password
|
74
|
+
# The password to check.
|
75
|
+
# @return [Boolean]
|
76
|
+
# True if the password provided is correct for the user.
|
77
|
+
#
|
78
|
+
# @!method self.authenticate
|
79
|
+
# Finds the user with the given email and authenticates them with the
|
80
|
+
# provided password. If the email corresponds to a user and the provided
|
81
|
+
# password is correct for that user, this method will return that user.
|
82
|
+
# Otherwise it will return nil.
|
83
|
+
#
|
84
|
+
# @return [User, nil]
|
85
|
+
#
|
86
|
+
# @!method self.find_by_normalized_email
|
87
|
+
# Finds the user with the given email. The email with be normalized via
|
88
|
+
# {#normalize_email}.
|
89
|
+
#
|
90
|
+
# @return [User, nil]
|
91
|
+
#
|
92
|
+
# @!method self.normalize_email
|
93
|
+
# Normalizes the provided email by downcasing and removing all spaces.
|
94
|
+
# This is used by {find_by_normalized_email} and is also called when
|
95
|
+
# validating a user to ensure only normalized emails are stored in the
|
96
|
+
# database.
|
97
|
+
#
|
98
|
+
# @return [String]
|
99
|
+
#
|
6
100
|
module User
|
7
101
|
extend ActiveSupport::Concern
|
8
102
|
|
9
103
|
included do
|
10
|
-
attr_accessor :password_changing
|
11
104
|
attr_reader :password
|
12
105
|
|
13
106
|
include Validations
|
14
107
|
include Callbacks
|
15
108
|
include password_strategy
|
109
|
+
|
110
|
+
def password=(value)
|
111
|
+
encrypted_password_will_change!
|
112
|
+
super
|
113
|
+
end
|
114
|
+
|
115
|
+
def password_changing
|
116
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] " \
|
117
|
+
"The `password_changing` attribute is deprecated. Clearance uses " \
|
118
|
+
"the dirty state of the `encrypted_password` field to track this " \
|
119
|
+
"automatically."
|
120
|
+
|
121
|
+
@password_changing
|
122
|
+
end
|
123
|
+
|
124
|
+
def password_changing=(value)
|
125
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] " \
|
126
|
+
"The `password_changing` attribute is deprecated. Clearance uses " \
|
127
|
+
"the dirty state of the `encrypted_password` field to track this " \
|
128
|
+
"automatically."
|
129
|
+
|
130
|
+
@password_changing = value
|
131
|
+
end
|
16
132
|
end
|
17
133
|
|
134
|
+
# @api private
|
18
135
|
module ClassMethods
|
19
136
|
def authenticate(email, password)
|
20
137
|
if user = find_by_normalized_email(email)
|
21
138
|
if password.present? && user.authenticated?(password)
|
22
|
-
|
139
|
+
user
|
23
140
|
end
|
24
141
|
end
|
25
142
|
end
|
@@ -39,6 +156,7 @@ module Clearance
|
|
39
156
|
end
|
40
157
|
end
|
41
158
|
|
159
|
+
# @api private
|
42
160
|
module Validations
|
43
161
|
extend ActiveSupport::Concern
|
44
162
|
|
@@ -53,6 +171,7 @@ module Clearance
|
|
53
171
|
end
|
54
172
|
end
|
55
173
|
|
174
|
+
# @api private
|
56
175
|
module Callbacks
|
57
176
|
extend ActiveSupport::Concern
|
58
177
|
|
@@ -62,18 +181,48 @@ module Clearance
|
|
62
181
|
end
|
63
182
|
end
|
64
183
|
|
184
|
+
# Generates a {#confirmation_token} for the user, which allows them to reset
|
185
|
+
# their password via an email link.
|
186
|
+
#
|
187
|
+
# Calling `forgot_password!` will cause the user model to be saved without
|
188
|
+
# validations. Any other changes you made to this user instance will also
|
189
|
+
# be persisted, without validation. It is inteded to be called on an
|
190
|
+
# instance with no changes (`dirty? == false`).
|
191
|
+
#
|
192
|
+
# @return [Boolean] Was the save successful?
|
65
193
|
def forgot_password!
|
66
194
|
generate_confirmation_token
|
67
195
|
save validate: false
|
68
196
|
end
|
69
197
|
|
198
|
+
# Generates a new {#remember_token} for the user, which will have the effect
|
199
|
+
# of signing all of the user's current sessions out. This is called
|
200
|
+
# internally by {Session#sign_out}.
|
201
|
+
#
|
202
|
+
# Calling `reset_remember_token!` will cause the user model to be saved
|
203
|
+
# without validations. Any other changes you made to this user instance will
|
204
|
+
# also be persisted, without validation. It is inteded to be called on an
|
205
|
+
# instance with no changes (`dirty? == false`).
|
206
|
+
#
|
207
|
+
# @return [Boolean] Was the save successful?
|
70
208
|
def reset_remember_token!
|
71
209
|
generate_remember_token
|
72
210
|
save validate: false
|
73
211
|
end
|
74
212
|
|
213
|
+
# Sets the user's password to the new value, using the `password=` method on
|
214
|
+
# the configured password strategy. By default, this is
|
215
|
+
# {PasswordStrategies::BCrypt#password=}.
|
216
|
+
#
|
217
|
+
# This also has the side-effect of blanking the {#confirmation_token} and
|
218
|
+
# rotating the `#remember_token`.
|
219
|
+
#
|
220
|
+
# Validations will be run as part of this update. If the user instance is
|
221
|
+
# not valid, the password change will not be persisted, and this method will
|
222
|
+
# return `false`.
|
223
|
+
#
|
224
|
+
# @return [Boolean] Was the save successful?
|
75
225
|
def update_password(new_password)
|
76
|
-
self.password_changing = true
|
77
226
|
self.password = new_password
|
78
227
|
|
79
228
|
if valid?
|
@@ -86,28 +235,58 @@ module Clearance
|
|
86
235
|
|
87
236
|
private
|
88
237
|
|
238
|
+
# Sets the email on this instance to the value returned by
|
239
|
+
# {.normalize_email}
|
240
|
+
#
|
241
|
+
# @return [String]
|
89
242
|
def normalize_email
|
90
243
|
self.email = self.class.normalize_email(email)
|
91
244
|
end
|
92
245
|
|
246
|
+
# Always false. Override this method in your user model to allow for other
|
247
|
+
# forms of user authentication (username, Facebook, etc).
|
248
|
+
#
|
249
|
+
# @return [false]
|
93
250
|
def email_optional?
|
94
251
|
false
|
95
252
|
end
|
96
253
|
|
254
|
+
# Always false. Override this method in your user model to allow for other
|
255
|
+
# forms of user authentication (username, Facebook, etc).
|
256
|
+
#
|
257
|
+
# @return [false]
|
97
258
|
def password_optional?
|
98
259
|
false
|
99
260
|
end
|
100
261
|
|
262
|
+
# True if {#password_optional?} is true or if the user already has an
|
263
|
+
# {#encrypted_password} that is not changing.
|
264
|
+
#
|
265
|
+
# @return [Boolean]
|
101
266
|
def skip_password_validation?
|
102
|
-
password_optional? ||
|
267
|
+
password_optional? ||
|
268
|
+
(encrypted_password.present? && !encrypted_password_changed?)
|
103
269
|
end
|
104
270
|
|
271
|
+
# Sets the {#confirmation_token} on the instance to a new value generated by
|
272
|
+
# {Token.new}. The change is not automatically persisted. If you would like
|
273
|
+
# to generate and save in a single method call, use {#forgot_password!}.
|
274
|
+
#
|
275
|
+
# @return [String] The new confirmation token
|
105
276
|
def generate_confirmation_token
|
106
277
|
self.confirmation_token = Clearance::Token.new
|
107
278
|
end
|
108
279
|
|
280
|
+
# Sets the {#remember_token} on the instance to a new value generated by
|
281
|
+
# {Token.new}. The change is not automatically persisted. If you would like
|
282
|
+
# to generate and save in a single method call, use
|
283
|
+
# {#reset_remember_token!}.
|
284
|
+
#
|
285
|
+
# @return [String] The new remember token
|
109
286
|
def generate_remember_token
|
110
287
|
self.remember_token = Clearance::Token.new
|
111
288
|
end
|
289
|
+
|
290
|
+
private_constant :Callbacks, :ClassMethods, :Validations
|
112
291
|
end
|
113
292
|
end
|
data/lib/clearance/version.rb
CHANGED
@@ -23,11 +23,12 @@ module Clearance
|
|
23
23
|
if File.exist? "app/models/user.rb"
|
24
24
|
inject_into_file(
|
25
25
|
"app/models/user.rb",
|
26
|
-
"include Clearance::User\n\n",
|
27
|
-
after: "class User <
|
26
|
+
" include Clearance::User\n\n",
|
27
|
+
after: "class User < #{models_inherit_from}\n",
|
28
28
|
)
|
29
29
|
else
|
30
|
-
|
30
|
+
@inherit_from = models_inherit_from
|
31
|
+
template("user.rb.erb", "app/models/user.rb")
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
@@ -35,7 +36,7 @@ module Clearance
|
|
35
36
|
if users_table_exists?
|
36
37
|
create_add_columns_migration
|
37
38
|
else
|
38
|
-
copy_migration
|
39
|
+
copy_migration "create_users"
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
@@ -52,16 +53,16 @@ module Clearance
|
|
52
53
|
new_indexes: new_indexes
|
53
54
|
}
|
54
55
|
|
55
|
-
copy_migration(
|
56
|
+
copy_migration("add_clearance_to_users", config)
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
59
60
|
def copy_migration(migration_name, config = {})
|
60
61
|
unless migration_exists?(migration_name)
|
61
62
|
migration_template(
|
62
|
-
"db/migrate/#{migration_name}",
|
63
|
-
"db/migrate/#{migration_name}",
|
64
|
-
config
|
63
|
+
"db/migrate/#{migration_name}.rb.erb",
|
64
|
+
"db/migrate/#{migration_name}.rb",
|
65
|
+
config.merge(migration_version: migration_version),
|
65
66
|
)
|
66
67
|
end
|
67
68
|
end
|
@@ -101,7 +102,11 @@ module Clearance
|
|
101
102
|
end
|
102
103
|
|
103
104
|
def users_table_exists?
|
104
|
-
ActiveRecord::Base.connection.
|
105
|
+
if ActiveRecord::Base.connection.respond_to?(:data_source_exists?)
|
106
|
+
ActiveRecord::Base.connection.data_source_exists?(:users)
|
107
|
+
else
|
108
|
+
ActiveRecord::Base.connection.table_exists?(:users)
|
109
|
+
end
|
105
110
|
end
|
106
111
|
|
107
112
|
def existing_users_columns
|
@@ -116,6 +121,20 @@ module Clearance
|
|
116
121
|
def self.next_migration_number(dir)
|
117
122
|
ActiveRecord::Generators::Base.next_migration_number(dir)
|
118
123
|
end
|
124
|
+
|
125
|
+
def migration_version
|
126
|
+
if Rails.version >= "5.0.0"
|
127
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def models_inherit_from
|
132
|
+
if Rails.version >= "5.0.0"
|
133
|
+
"ApplicationRecord"
|
134
|
+
else
|
135
|
+
"ActiveRecord::Base"
|
136
|
+
end
|
137
|
+
end
|
119
138
|
end
|
120
139
|
end
|
121
140
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
class AddClearanceToUsers < ActiveRecord::Migration
|
1
|
+
class AddClearanceToUsers < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def self.up
|
3
|
-
change_table :users
|
3
|
+
change_table :users do |t|
|
4
4
|
<% config[:new_columns].values.each do |column| -%>
|
5
5
|
<%= column %>
|
6
6
|
<% end -%>
|
@@ -24,7 +24,7 @@ class AddClearanceToUsers < ActiveRecord::Migration
|
|
24
24
|
def self.down
|
25
25
|
change_table :users do |t|
|
26
26
|
<% if config[:new_columns].any? -%>
|
27
|
-
t.remove <%= new_columns.keys.map { |column| ":#{column}" }.join(",") %>
|
27
|
+
t.remove <%= new_columns.keys.map { |column| ":#{column}" }.join(", ") %>
|
28
28
|
<% end -%>
|
29
29
|
end
|
30
30
|
end
|
data/lib/generators/clearance/install/templates/db/migrate/{create_users.rb → create_users.rb.erb}
RENAMED
@@ -1,6 +1,6 @@
|
|
1
|
-
class CreateUsers < ActiveRecord::Migration
|
1
|
+
class CreateUsers < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def change
|
3
|
-
create_table :users
|
3
|
+
create_table :users do |t|
|
4
4
|
t.timestamps null: false
|
5
5
|
t.string :email, null: false
|
6
6
|
t.string :encrypted_password, limit: 128, null: false
|
@@ -9,6 +9,14 @@ module Clearance
|
|
9
9
|
route(clearance_routes)
|
10
10
|
end
|
11
11
|
|
12
|
+
def disable_clearance_internal_routes
|
13
|
+
inject_into_file(
|
14
|
+
"config/initializers/clearance.rb",
|
15
|
+
" config.routes = false\n",
|
16
|
+
after: "Clearance.configure do |config|\n",
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
12
20
|
private
|
13
21
|
|
14
22
|
def clearance_routes
|
@@ -18,6 +26,21 @@ module Clearance
|
|
18
26
|
def routes_file_path
|
19
27
|
File.expand_path(find_in_source_paths('routes.rb'))
|
20
28
|
end
|
29
|
+
|
30
|
+
def route(routing_code)
|
31
|
+
log :route, "all clearance routes"
|
32
|
+
sentinel = /\.routes\.draw do\s*\n/m
|
33
|
+
|
34
|
+
in_root do
|
35
|
+
inject_into_file(
|
36
|
+
"config/routes.rb",
|
37
|
+
routing_code,
|
38
|
+
after: sentinel,
|
39
|
+
verbose: false,
|
40
|
+
force: true,
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
21
44
|
end
|
22
45
|
end
|
23
46
|
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
resources :passwords, controller:
|
2
|
-
resource :session, controller:
|
1
|
+
resources :passwords, controller: "clearance/passwords", only: [:create, :new]
|
2
|
+
resource :session, controller: "clearance/sessions", only: [:create]
|
3
3
|
|
4
|
-
resources :users, controller:
|
4
|
+
resources :users, controller: "clearance/users", only: [:create] do
|
5
5
|
resource :password,
|
6
|
-
controller:
|
6
|
+
controller: "clearance/passwords",
|
7
7
|
only: [:create, :edit, :update]
|
8
8
|
end
|
9
9
|
|
10
|
-
get
|
11
|
-
delete
|
12
|
-
get
|
10
|
+
get "/sign_in" => "clearance/sessions#new", as: "sign_in"
|
11
|
+
delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
|
12
|
+
get "/sign_up" => "clearance/users#new", as: "sign_up"
|
data/lib/generators/clearance/specs/templates/features/clearance/visitor_resets_password_spec.rb.tt
CHANGED
@@ -1,8 +1,17 @@
|
|
1
1
|
require "<%= @helper_file %>"
|
2
2
|
require "support/features/clearance_helpers"
|
3
3
|
|
4
|
-
feature "Visitor resets password" do
|
4
|
+
RSpec.feature "Visitor resets password" do
|
5
5
|
before { ActionMailer::Base.deliveries.clear }
|
6
|
+
<% if defined?(ActiveJob) -%>
|
7
|
+
|
8
|
+
around do |example|
|
9
|
+
original_adapter = ActiveJob::Base.queue_adapter
|
10
|
+
ActiveJob::Base.queue_adapter = :inline
|
11
|
+
example.run
|
12
|
+
ActiveJob::Base.queue_adapter = original_adapter
|
13
|
+
end
|
14
|
+
<% end -%>
|
6
15
|
|
7
16
|
scenario "by navigating to the page" do
|
8
17
|
visit sign_in_path
|
@@ -33,7 +42,7 @@ feature "Visitor resets password" do
|
|
33
42
|
expect_mailer_to_have_delivery(
|
34
43
|
user.email,
|
35
44
|
"password",
|
36
|
-
user.confirmation_token
|
45
|
+
user.confirmation_token,
|
37
46
|
)
|
38
47
|
end
|
39
48
|
|
@@ -47,7 +56,7 @@ feature "Visitor resets password" do
|
|
47
56
|
message = ActionMailer::Base.deliveries.any? do |email|
|
48
57
|
email.to == [recipient] &&
|
49
58
|
email.subject =~ /#{subject}/i &&
|
50
|
-
email.html_part.body =~ /#{body}/
|
59
|
+
email.html_part.body =~ /#{body}/ &&
|
51
60
|
email.text_part.body =~ /#{body}/
|
52
61
|
end
|
53
62
|
|
data/lib/generators/clearance/specs/templates/features/clearance/visitor_signs_in_spec.rb.tt
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "<%= @helper_file %>"
|
2
2
|
require "support/features/clearance_helpers"
|
3
3
|
|
4
|
-
feature "Visitor signs in" do
|
4
|
+
RSpec.feature "Visitor signs in" do
|
5
5
|
scenario "with valid email and password" do
|
6
6
|
create_user "user@example.com", "password"
|
7
7
|
sign_in_with "user@example.com", "password"
|
@@ -34,12 +34,12 @@ feature "Visitor signs in" do
|
|
34
34
|
private
|
35
35
|
|
36
36
|
def create_user(email, password)
|
37
|
-
|
37
|
+
FactoryBot.create(:user, email: email, password: password)
|
38
38
|
end
|
39
39
|
|
40
40
|
def expect_page_to_display_sign_in_error
|
41
41
|
expect(page.body).to include(
|
42
|
-
I18n.t("flashes.failure_after_create", sign_up_path: sign_up_path)
|
42
|
+
I18n.t("flashes.failure_after_create", sign_up_path: sign_up_path),
|
43
43
|
)
|
44
44
|
end
|
45
45
|
end
|
data/lib/generators/clearance/specs/templates/features/clearance/visitor_updates_password_spec.rb.tt
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "<%= @helper_file %>"
|
2
2
|
require "support/features/clearance_helpers"
|
3
3
|
|
4
|
-
feature "Visitor updates password" do
|
4
|
+
RSpec.feature "Visitor updates password" do
|
5
5
|
scenario "with valid password" do
|
6
6
|
user = user_with_reset_password
|
7
7
|
update_password user, "newpassword"
|
@@ -37,7 +37,7 @@ feature "Visitor updates password" do
|
|
37
37
|
def visit_password_reset_page_for(user)
|
38
38
|
visit edit_user_password_path(
|
39
39
|
user_id: user,
|
40
|
-
token: user.confirmation_token
|
40
|
+
token: user.confirmation_token,
|
41
41
|
)
|
42
42
|
end
|
43
43
|
|
@@ -8,7 +8,7 @@ module Features
|
|
8
8
|
|
9
9
|
def sign_in
|
10
10
|
password = "password"
|
11
|
-
user =
|
11
|
+
user = FactoryBot.create(:user, password: password)
|
12
12
|
sign_in_with user.email, password
|
13
13
|
end
|
14
14
|
|
@@ -40,7 +40,7 @@ module Features
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def user_with_reset_password
|
43
|
-
user =
|
43
|
+
user = FactoryBot.create(:user)
|
44
44
|
reset_password_for user.email
|
45
45
|
user.reload
|
46
46
|
end
|