clearance 1.8.0 → 1.16.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 +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +25 -6
- data/.yardopts +6 -0
- data/Appraisals +15 -4
- data/CONTRIBUTING.md +4 -1
- data/Gemfile +5 -3
- data/Gemfile.lock +102 -96
- data/NEWS.md +742 -311
- data/README.md +217 -339
- data/app/controllers/clearance/passwords_controller.rb +35 -21
- data/app/controllers/clearance/sessions_controller.rb +17 -4
- data/app/controllers/clearance/users_controller.rb +10 -4
- data/app/mailers/clearance_mailer.rb +2 -3
- data/app/views/clearance_mailer/change_password.html.erb +6 -3
- data/app/views/clearance_mailer/change_password.text.erb +5 -0
- data/app/views/layouts/application.html.erb +2 -2
- data/app/views/passwords/create.html.erb +1 -1
- data/app/views/passwords/edit.html.erb +2 -2
- data/app/views/passwords/new.html.erb +2 -2
- data/app/views/sessions/_form.html.erb +2 -2
- data/app/views/sessions/new.html.erb +1 -1
- data/app/views/users/new.html.erb +2 -2
- data/bin/setup +6 -2
- data/config/locales/clearance.en.yml +6 -0
- data/db/migrate/20110111224543_create_clearance_users.rb +1 -1
- data/gemfiles/{rails3.2.gemfile → rails32.gemfile} +4 -2
- data/gemfiles/{rails4.0.gemfile → rails40.gemfile} +6 -3
- data/gemfiles/{rails4.1.gemfile → rails41.gemfile} +6 -3
- data/gemfiles/{rails4.2.gemfile → rails42.gemfile} +6 -3
- data/gemfiles/rails50.gemfile +21 -0
- data/lib/clearance/authentication.rb +61 -2
- data/lib/clearance/authorization.rb +47 -4
- data/lib/clearance/back_door.rb +29 -6
- data/lib/clearance/configuration.rb +152 -15
- 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 +24 -4
- data/lib/clearance/password_strategies/bcrypt.rb +16 -21
- data/lib/clearance/password_strategies/bcrypt_migration_from_sha1.rb +19 -0
- data/lib/clearance/password_strategies/blowfish.rb +17 -0
- data/lib/clearance/password_strategies/sha1.rb +17 -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 +46 -1
- 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 +44 -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 +182 -4
- data/lib/clearance/version.rb +1 -1
- data/lib/clearance.rb +2 -0
- data/lib/generators/clearance/install/install_generator.rb +24 -5
- data/lib/generators/clearance/install/templates/clearance.rb +1 -0
- data/lib/generators/clearance/install/templates/db/migrate/add_clearance_to_users.rb +3 -3
- data/lib/generators/clearance/install/templates/db/migrate/create_users.rb +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/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 -2
- data/lib/generators/clearance/specs/templates/features/clearance/visitor_signs_in_spec.rb.tt +1 -1
- 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 +1 -1
- data/spec/acceptance/clearance_installation_spec.rb +4 -1
- 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/app/controllers/home_controller.rb +5 -1
- data/spec/app_templates/testapp/config/initializers/action_mailer.rb +1 -3
- data/spec/clearance/back_door_spec.rb +25 -6
- data/spec/clearance/controller_spec.rb +11 -0
- data/spec/clearance/rack_session_spec.rb +5 -5
- data/spec/clearance/session_spec.rb +2 -15
- data/spec/clearance/testing/{helpers_spec.rb → controller_helpers_spec.rb} +12 -12
- data/spec/clearance/testing/view_helpers_spec.rb +37 -0
- data/spec/configuration_spec.rb +94 -86
- data/spec/controllers/apis_controller_spec.rb +6 -2
- data/spec/controllers/forgeries_controller_spec.rb +6 -1
- data/spec/controllers/passwords_controller_spec.rb +17 -16
- data/spec/controllers/permissions_controller_spec.rb +13 -3
- data/spec/controllers/sessions_controller_spec.rb +4 -4
- data/spec/dummy/app/controllers/application_controller.rb +5 -1
- data/spec/dummy/application.rb +4 -0
- data/spec/generators/clearance/install/install_generator_spec.rb +29 -3
- data/spec/generators/clearance/routes/routes_generator_spec.rb +5 -1
- data/spec/generators/clearance/views/views_generator_spec.rb +11 -10
- data/spec/helpers/helper_helpers_spec.rb +10 -0
- data/spec/mailers/clearance_mailer_spec.rb +13 -19
- data/spec/password_strategies/bcrypt_migration_from_sha1_spec.rb +6 -0
- data/spec/password_strategies/blowfish_spec.rb +6 -0
- data/spec/password_strategies/sha1_spec.rb +6 -0
- data/spec/requests/csrf_rotation_spec.rb +33 -0
- data/spec/spec_helper.rb +11 -2
- data/spec/support/generator_spec_helpers.rb +13 -1
- data/spec/support/http_method_shim.rb +23 -0
- data/spec/user_spec.rb +9 -0
- data/spec/views/view_helpers_spec.rb +10 -0
- metadata +22 -9
- data/lib/generators/clearance/install/templates/user.rb +0 -3
data/lib/clearance/user.rb
CHANGED
@@ -3,23 +3,139 @@ require 'email_validator'
|
|
3
3
|
require 'clearance/token'
|
4
4
|
|
5
5
|
module Clearance
|
6
|
+
# Required to be included in your configued user class, which is `User` by
|
7
|
+
# default, but can be changed with {Configuration#user_model=}.
|
8
|
+
#
|
9
|
+
# class User
|
10
|
+
# include Clearance::User
|
11
|
+
#
|
12
|
+
# # ...
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# This will also include methods exposed by your password strategy, which can
|
16
|
+
# be configured with {Configuration#password_strategy=}. By default, this is
|
17
|
+
# {PasswordStrategies::BCrypt}.
|
18
|
+
#
|
19
|
+
# ## Validations
|
20
|
+
#
|
21
|
+
# These validations are added to the class that the {User} module is mixed
|
22
|
+
# into.
|
23
|
+
#
|
24
|
+
# * If {#email_optional?} is false, {#email} is validated for presence,
|
25
|
+
# uniqueness and email format (using the `email_validator` gem in strict
|
26
|
+
# mode).
|
27
|
+
# * If {#skip_password_validation?} is false, {#password} is validated
|
28
|
+
# for presence.
|
29
|
+
#
|
30
|
+
# ## Callbacks
|
31
|
+
#
|
32
|
+
# * {#normalize_email} will be called on `before_validation`
|
33
|
+
# * {#generate_remember_token} will be called on `before_create`
|
34
|
+
#
|
35
|
+
# @!attribute email
|
36
|
+
# @return [String] The user's email.
|
37
|
+
#
|
38
|
+
# @!attribute encrypted_password
|
39
|
+
# @return [String] The user's encrypted password.
|
40
|
+
#
|
41
|
+
# @!attribute remember_token
|
42
|
+
# @return [String] The value used to identify this user in their {Session}
|
43
|
+
# cookie.
|
44
|
+
#
|
45
|
+
# @!attribute confirmation_token
|
46
|
+
# @return [String] The value used to identify this user in the password
|
47
|
+
# reset link.
|
48
|
+
#
|
49
|
+
# @!attribute password_changing
|
50
|
+
# @deprecated Dirty tracking is now handled automatically.
|
51
|
+
#
|
52
|
+
# @!attribute [r] password
|
53
|
+
# @return [String] Transient (non-persisted) attribute that is set when
|
54
|
+
# updating a user's password. Only the {#encrypted_password} is persisted.
|
55
|
+
#
|
56
|
+
# @!method password=
|
57
|
+
# Sets the user's encrypted_password by using the configured Password
|
58
|
+
# Strategy's `password=` method. By default, this will be
|
59
|
+
# {PasswordStrategies::BCrypt#password=}, but can be changed with
|
60
|
+
# {Configuration#password_strategy}.
|
61
|
+
#
|
62
|
+
# @see PasswordStrategies
|
63
|
+
# @return [void]
|
64
|
+
#
|
65
|
+
# @!method authenticated?
|
66
|
+
# Check's the provided password against the user's encrypted password using
|
67
|
+
# the configured password strategy. By default, this will be
|
68
|
+
# {PasswordStrategies::BCrypt#authenticated?}, but can be changed with
|
69
|
+
# {Configuration#password_strategy}.
|
70
|
+
#
|
71
|
+
# @see PasswordStrategies
|
72
|
+
# @param [String] password
|
73
|
+
# The password to check.
|
74
|
+
# @return [Boolean]
|
75
|
+
# True if the password provided is correct for the user.
|
76
|
+
#
|
77
|
+
# @!method self.authenticate
|
78
|
+
# Finds the user with the given email and authenticates them with the
|
79
|
+
# provided password. If the email corresponds to a user and the provided
|
80
|
+
# password is correct for that user, this method will return that user.
|
81
|
+
# Otherwise it will return nil.
|
82
|
+
#
|
83
|
+
# @return [User, nil]
|
84
|
+
#
|
85
|
+
# @!method self.find_by_normalized_email
|
86
|
+
# Finds the user with the given email. The email with be normalized via
|
87
|
+
# {#normalize_email}.
|
88
|
+
#
|
89
|
+
# @return [User, nil]
|
90
|
+
#
|
91
|
+
# @!method self.normalize_email
|
92
|
+
# Normalizes the provided email by downcasing and removing all spaces.
|
93
|
+
# This is used by {find_by_normalized_email} and is also called when
|
94
|
+
# validating a user to ensure only normalized emails are stored in the
|
95
|
+
# database.
|
96
|
+
#
|
97
|
+
# @return [String]
|
98
|
+
#
|
6
99
|
module User
|
7
100
|
extend ActiveSupport::Concern
|
8
101
|
|
9
102
|
included do
|
10
|
-
attr_accessor :password_changing
|
11
103
|
attr_reader :password
|
12
104
|
|
13
105
|
include Validations
|
14
106
|
include Callbacks
|
15
107
|
include password_strategy
|
108
|
+
|
109
|
+
def password=(value)
|
110
|
+
encrypted_password_will_change!
|
111
|
+
super
|
112
|
+
end
|
113
|
+
|
114
|
+
def password_changing
|
115
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] " \
|
116
|
+
"The `password_changing` attribute is deprecated. Clearance uses " \
|
117
|
+
"the dirty state of the `encrypted_password` field to track this " \
|
118
|
+
"automatically."
|
119
|
+
|
120
|
+
@password_changing
|
121
|
+
end
|
122
|
+
|
123
|
+
def password_changing=(value)
|
124
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] " \
|
125
|
+
"The `password_changing` attribute is deprecated. Clearance uses " \
|
126
|
+
"the dirty state of the `encrypted_password` field to track this " \
|
127
|
+
"automatically."
|
128
|
+
|
129
|
+
@password_changing = value
|
130
|
+
end
|
16
131
|
end
|
17
132
|
|
133
|
+
# @api private
|
18
134
|
module ClassMethods
|
19
135
|
def authenticate(email, password)
|
20
136
|
if user = find_by_normalized_email(email)
|
21
137
|
if password.present? && user.authenticated?(password)
|
22
|
-
|
138
|
+
user
|
23
139
|
end
|
24
140
|
end
|
25
141
|
end
|
@@ -39,6 +155,7 @@ module Clearance
|
|
39
155
|
end
|
40
156
|
end
|
41
157
|
|
158
|
+
# @api private
|
42
159
|
module Validations
|
43
160
|
extend ActiveSupport::Concern
|
44
161
|
|
@@ -53,6 +170,7 @@ module Clearance
|
|
53
170
|
end
|
54
171
|
end
|
55
172
|
|
173
|
+
# @api private
|
56
174
|
module Callbacks
|
57
175
|
extend ActiveSupport::Concern
|
58
176
|
|
@@ -62,18 +180,48 @@ module Clearance
|
|
62
180
|
end
|
63
181
|
end
|
64
182
|
|
183
|
+
# Generates a {#confirmation_token} for the user, which allows them to reset
|
184
|
+
# their password via an email link.
|
185
|
+
#
|
186
|
+
# Calling `forgot_password!` will cause the user model to be saved without
|
187
|
+
# validations. Any other changes you made to this user instance will also
|
188
|
+
# be persisted, without validation. It is inteded to be called on an
|
189
|
+
# instance with no changes (`dirty? == false`).
|
190
|
+
#
|
191
|
+
# @return [Boolean] Was the save successful?
|
65
192
|
def forgot_password!
|
66
193
|
generate_confirmation_token
|
67
194
|
save validate: false
|
68
195
|
end
|
69
196
|
|
197
|
+
# Generates a new {#remember_token} for the user, which will have the effect
|
198
|
+
# of signing all of the user's current sessions out. This is called
|
199
|
+
# internally by {Session#sign_out}.
|
200
|
+
#
|
201
|
+
# Calling `reset_remember_token!` will cause the user model to be saved
|
202
|
+
# without validations. Any other changes you made to this user instance will
|
203
|
+
# also be persisted, without validation. It is inteded to be called on an
|
204
|
+
# instance with no changes (`dirty? == false`).
|
205
|
+
#
|
206
|
+
# @return [Boolean] Was the save successful?
|
70
207
|
def reset_remember_token!
|
71
208
|
generate_remember_token
|
72
209
|
save validate: false
|
73
210
|
end
|
74
211
|
|
212
|
+
# Sets the user's password to the new value, using the `password=` method on
|
213
|
+
# the configured password strategy. By default, this is
|
214
|
+
# {PasswordStrategies::BCrypt#password=}.
|
215
|
+
#
|
216
|
+
# This also has the side-effect of blanking the {#confirmation_token} and
|
217
|
+
# rotating the `#remember_token`.
|
218
|
+
#
|
219
|
+
# Validations will be run as part of this update. If the user instance is
|
220
|
+
# not valid, the password change will not be persisted, and this method will
|
221
|
+
# return `false`.
|
222
|
+
#
|
223
|
+
# @return [Boolean] Was the save successful?
|
75
224
|
def update_password(new_password)
|
76
|
-
self.password_changing = true
|
77
225
|
self.password = new_password
|
78
226
|
|
79
227
|
if valid?
|
@@ -86,28 +234,58 @@ module Clearance
|
|
86
234
|
|
87
235
|
private
|
88
236
|
|
237
|
+
# Sets the email on this instance to the value returned by
|
238
|
+
# {.normalize_email}
|
239
|
+
#
|
240
|
+
# @return [String]
|
89
241
|
def normalize_email
|
90
242
|
self.email = self.class.normalize_email(email)
|
91
243
|
end
|
92
244
|
|
245
|
+
# Always false. Override this method in your user model to allow for other
|
246
|
+
# forms of user authentication (username, Facebook, etc).
|
247
|
+
#
|
248
|
+
# @return [false]
|
93
249
|
def email_optional?
|
94
250
|
false
|
95
251
|
end
|
96
252
|
|
253
|
+
# Always false. Override this method in your user model to allow for other
|
254
|
+
# forms of user authentication (username, Facebook, etc).
|
255
|
+
#
|
256
|
+
# @return [false]
|
97
257
|
def password_optional?
|
98
258
|
false
|
99
259
|
end
|
100
260
|
|
261
|
+
# True if {#password_optional?} is true or if the user already has an
|
262
|
+
# {#encrypted_password} that is not changing.
|
263
|
+
#
|
264
|
+
# @return [Boolean]
|
101
265
|
def skip_password_validation?
|
102
|
-
password_optional? ||
|
266
|
+
password_optional? ||
|
267
|
+
(encrypted_password.present? && !encrypted_password_changed?)
|
103
268
|
end
|
104
269
|
|
270
|
+
# Sets the {#confirmation_token} on the instance to a new value generated by
|
271
|
+
# {Token.new}. The change is not automatically persisted. If you would like
|
272
|
+
# to generate and save in a single method call, use {#forgot_password!}.
|
273
|
+
#
|
274
|
+
# @return [String] The new confirmation token
|
105
275
|
def generate_confirmation_token
|
106
276
|
self.confirmation_token = Clearance::Token.new
|
107
277
|
end
|
108
278
|
|
279
|
+
# Sets the {#remember_token} on the instance to a new value generated by
|
280
|
+
# {Token.new}. The change is not automatically persisted. If you would like
|
281
|
+
# to generate and save in a single method call, use
|
282
|
+
# {#reset_remember_token!}.
|
283
|
+
#
|
284
|
+
# @return [String] The new remember token
|
109
285
|
def generate_remember_token
|
110
286
|
self.remember_token = Clearance::Token.new
|
111
287
|
end
|
288
|
+
|
289
|
+
private_constant :Callbacks, :ClassMethods, :Validations
|
112
290
|
end
|
113
291
|
end
|
data/lib/clearance/version.rb
CHANGED
data/lib/clearance.rb
CHANGED
@@ -10,6 +10,8 @@ require 'clearance/password_strategies'
|
|
10
10
|
require 'clearance/constraints'
|
11
11
|
|
12
12
|
module Clearance
|
13
|
+
# @deprecated Use `Gem::Specification` API if you need to access Clearance's
|
14
|
+
# Gem root.
|
13
15
|
def self.root
|
14
16
|
warn "#{Kernel.caller.first}: [DEPRECATION] `Clearance.root` is " +
|
15
17
|
"deprecated and will be removed in the next major release. If you need " +
|
@@ -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
|
|
@@ -61,7 +62,7 @@ module Clearance
|
|
61
62
|
migration_template(
|
62
63
|
"db/migrate/#{migration_name}",
|
63
64
|
"db/migrate/#{migration_name}",
|
64
|
-
config
|
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
|
@@ -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
|
@@ -47,7 +56,8 @@ 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.body =~ /#{body}/
|
59
|
+
email.html_part.body =~ /#{body}/ &&
|
60
|
+
email.text_part.body =~ /#{body}/
|
51
61
|
end
|
52
62
|
|
53
63
|
expect(message).to be
|
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"
|
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"
|
@@ -10,6 +10,7 @@ describe "Clearance Installation" do
|
|
10
10
|
|
11
11
|
it "can successfully run specs" do
|
12
12
|
app_name = "testapp"
|
13
|
+
|
13
14
|
generate_test_app(app_name)
|
14
15
|
|
15
16
|
Dir.chdir(app_name) do
|
@@ -28,7 +29,8 @@ describe "Clearance Installation" do
|
|
28
29
|
--skip-git \
|
29
30
|
--skip-javascript \
|
30
31
|
--skip-sprockets \
|
31
|
-
--skip-keeps
|
32
|
+
--skip-keeps \
|
33
|
+
--no-rc"
|
32
34
|
|
33
35
|
FileUtils.rm_f("public/index.html")
|
34
36
|
FileUtils.rm_f("app/views/layouts/application.html.erb")
|
@@ -70,6 +72,7 @@ describe "Clearance Installation" do
|
|
70
72
|
end
|
71
73
|
|
72
74
|
return_value = system("#{command} #{silencer}")
|
75
|
+
|
73
76
|
expect(return_value).to eq true
|
74
77
|
end
|
75
78
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe Clearance::BackDoor do
|
4
|
-
it
|
5
|
-
user_id =
|
4
|
+
it "signs in as a given user" do
|
5
|
+
user_id = "123"
|
6
6
|
user = double("user")
|
7
7
|
allow(User).to receive(:find).with(user_id).and_return(user)
|
8
8
|
env = env_for_user_id(user_id)
|
@@ -14,7 +14,7 @@ describe Clearance::BackDoor do
|
|
14
14
|
expect(result).to eq mock_app.call(env)
|
15
15
|
end
|
16
16
|
|
17
|
-
it
|
17
|
+
it "delegates directly without a user" do
|
18
18
|
env = env_without_user_id
|
19
19
|
back_door = Clearance::BackDoor.new(mock_app)
|
20
20
|
|
@@ -24,8 +24,22 @@ describe Clearance::BackDoor do
|
|
24
24
|
expect(result).to eq mock_app.call(env)
|
25
25
|
end
|
26
26
|
|
27
|
+
it "can set the user via a block" do
|
28
|
+
env = env_for_username("foo")
|
29
|
+
user = double("user")
|
30
|
+
allow(User).to receive(:find_by).with(username: "foo").and_return(user)
|
31
|
+
back_door = Clearance::BackDoor.new(mock_app) do |username|
|
32
|
+
User.find_by(username: username)
|
33
|
+
end
|
34
|
+
|
35
|
+
result = back_door.call(env)
|
36
|
+
|
37
|
+
expect(env[:clearance]).to have_received(:sign_in).with(user)
|
38
|
+
expect(result).to eq mock_app.call(env)
|
39
|
+
end
|
40
|
+
|
27
41
|
def env_without_user_id
|
28
|
-
env_for_user_id(
|
42
|
+
env_for_user_id("")
|
29
43
|
end
|
30
44
|
|
31
45
|
def env_for_user_id(user_id)
|
@@ -33,7 +47,12 @@ describe Clearance::BackDoor do
|
|
33
47
|
Rack::MockRequest.env_for("/?as=#{user_id}").merge(clearance: clearance)
|
34
48
|
end
|
35
49
|
|
50
|
+
def env_for_username(username)
|
51
|
+
clearance = double("clearance", sign_in: true)
|
52
|
+
Rack::MockRequest.env_for("/?as=#{username}").merge(clearance: clearance)
|
53
|
+
end
|
54
|
+
|
36
55
|
def mock_app
|
37
|
-
lambda { |env| [200, {}, [
|
56
|
+
lambda { |env| [200, {}, ["okay"]] }
|
38
57
|
end
|
39
58
|
end
|
@@ -2,21 +2,21 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Clearance::RackSession do
|
4
4
|
it 'injects a clearance session into the environment' do
|
5
|
-
expected_session = 'the session'
|
6
|
-
allow(expected_session).to receive(:add_cookie_to_headers)
|
7
|
-
allow(Clearance::Session).to receive(:new).and_return(expected_session)
|
8
5
|
headers = { 'X-Roaring-Lobster' => 'Red' }
|
9
|
-
|
10
6
|
app = Rack::Builder.new do
|
11
7
|
use Clearance::RackSession
|
12
8
|
run lambda { |env| Rack::Response.new(env[:clearance], 200, headers).finish }
|
13
9
|
end
|
14
10
|
|
15
11
|
env = Rack::MockRequest.env_for('/')
|
12
|
+
expected_session = "the session"
|
13
|
+
allow(expected_session).to receive(:add_cookie_to_headers)
|
14
|
+
allow(Clearance::Session).to receive(:new).
|
15
|
+
with(env).
|
16
|
+
and_return(expected_session)
|
16
17
|
|
17
18
|
response = Rack::MockResponse.new(*app.call(env))
|
18
19
|
|
19
|
-
expect(Clearance::Session).to have_received(:new).with(env)
|
20
20
|
expect(response.body).to eq expected_session
|
21
21
|
expect(expected_session).to have_received(:add_cookie_to_headers).
|
22
22
|
with(hash_including(headers))
|