thoughtbot-clearance 0.4.4 → 0.4.5
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.
- data/CHANGELOG.textile +11 -0
- data/README.textile +14 -10
- data/Rakefile +1 -1
- data/generators/clearance_features/clearance_features_generator.rb +2 -1
- data/generators/clearance_features/templates/features/password_reset.feature +1 -1
- data/generators/clearance_features/templates/features/sign_in.feature +2 -2
- data/generators/clearance_features/templates/features/step_definitions/clearance_steps.rb +0 -3
- data/lib/clearance/app/controllers/application_controller.rb +3 -4
- data/lib/clearance/app/models/user.rb +4 -8
- data/lib/clearance/test/test_helper.rb +0 -2
- data/lib/clearance/test/unit/user_test.rb +14 -15
- data/shoulda_macros/clearance.rb +0 -4
- metadata +2 -3
- data/TODO.textile +0 -8
data/CHANGELOG.textile
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
h2. 0.4.5 (unreleased)
|
2
|
+
|
3
|
+
* [#43] Removed email downcasing. (local-part is case sensitive per RFC5321)
|
4
|
+
* [#42] Removed dependency on Mocha.
|
5
|
+
* Required Shoulda >= 2.9.1.
|
6
|
+
* Added password reset feature to clearance_features generator.
|
7
|
+
* Removed unnecessary session[:salt].
|
8
|
+
* [#41] Only store location for session[:return_to] for GET requests.
|
9
|
+
* Audited "sign up" naming convention. "Register" had slipped in a few places.
|
10
|
+
* Switched to SHA1 encryption. Cypher doesn't matter much for email confirmation, password reset. Better to have shorter hashes in the emails for clients who line break on 72 chars.
|
11
|
+
|
1
12
|
h2. 0.4.4 (2/2/2009)
|
2
13
|
|
3
14
|
* Added a generator for Cucumber features
|
data/README.textile
CHANGED
@@ -12,24 +12,28 @@ h2. Gem installation (Rails 2.1+)
|
|
12
12
|
|
13
13
|
In config/environment.rb:
|
14
14
|
|
15
|
-
config.gem
|
15
|
+
config.gem "thoughtbot-clearance",
|
16
|
+
:lib => 'clearance',
|
17
|
+
:source => 'http://gems.github.com',
|
18
|
+
:version => '>= 0.4.3'
|
19
|
+
|
20
|
+
In config/environments/test.rb:
|
21
|
+
|
16
22
|
config.gem 'thoughtbot-shoulda',
|
17
23
|
:lib => 'shoulda',
|
18
24
|
:source => "http://gems.github.com",
|
19
|
-
:version => '>= 2.
|
25
|
+
:version => '>= 2.9.1'
|
20
26
|
config.gem 'thoughtbot-factory_girl',
|
21
27
|
:lib => 'factory_girl',
|
22
28
|
:source => "http://gems.github.com",
|
23
29
|
:version => '>= 1.1.5'
|
24
|
-
config.gem "thoughtbot-clearance",
|
25
|
-
:lib => 'clearance',
|
26
|
-
:source => 'http://gems.github.com',
|
27
|
-
:version => '>= 0.3.9'
|
28
30
|
|
29
31
|
Then:
|
30
32
|
|
31
33
|
rake gems:install
|
32
|
-
rake gems:unpack
|
34
|
+
rake gems:unpack
|
35
|
+
rake gems:install RAILS_ENV=test
|
36
|
+
rake gems:unpack RAILS_ENV=test
|
33
37
|
|
34
38
|
h2. The generator
|
35
39
|
|
@@ -93,7 +97,7 @@ In config/environment.rb:
|
|
93
97
|
|
94
98
|
h2. Tests
|
95
99
|
|
96
|
-
The tests use "Shoulda":http://thoughtbot.com/projects/shoulda >= 2.
|
100
|
+
The tests use "Shoulda":http://thoughtbot.com/projects/shoulda >= 2.9.1 and "Factory Girl":http://thoughtbot.com/projects/factory_girl >= 1.1.5. There needs to be a Clearance module in your test/test_helper.rb:
|
97
101
|
|
98
102
|
class Test::Unit::TestCase
|
99
103
|
self.use_transactional_fixtures = true
|
@@ -108,7 +112,7 @@ h2. Usage: basic workflow
|
|
108
112
|
|
109
113
|
Rails authentication with Clearance uses the standard approach thoughtbot and our clients have agreed upon.
|
110
114
|
|
111
|
-
Users
|
115
|
+
Users sign up (UsersController) using an email address and a password (User model). They get an email (ClearanceMailer) with a confirmation link to confirm their registration (ConfirmationController).
|
112
116
|
|
113
117
|
Registered users can sign in and out (SessionsController). If they forget their password, they request an email (ClearanceMailer) containing a link to change it (PasswordsController).
|
114
118
|
|
@@ -169,7 +173,7 @@ Actions that redirect (create, update, and destroy) in Clearance controllers are
|
|
169
173
|
|
170
174
|
There are similar methods in other controllers as well:
|
171
175
|
|
172
|
-
UsersController#url_after_create (
|
176
|
+
UsersController#url_after_create (sign up)
|
173
177
|
SessionsController#url_after_create (sign in)
|
174
178
|
SessionsController#url_after_destroy (sign out)
|
175
179
|
PasswordsController#url_after_create (password request)
|
data/Rakefile
CHANGED
@@ -50,7 +50,7 @@ task :default => ['test:all', 'test:features']
|
|
50
50
|
|
51
51
|
gem_spec = Gem::Specification.new do |gem_spec|
|
52
52
|
gem_spec.name = "clearance"
|
53
|
-
gem_spec.version = "0.4.
|
53
|
+
gem_spec.version = "0.4.5"
|
54
54
|
gem_spec.summary = "Rails authentication for developers who write tests."
|
55
55
|
gem_spec.email = "support@thoughtbot.com"
|
56
56
|
gem_spec.homepage = "http://github.com/thoughtbot/clearance"
|
@@ -7,7 +7,8 @@ class ClearanceFeaturesGenerator < Rails::Generator::Base
|
|
7
7
|
["features/step_definitions/clearance_steps.rb",
|
8
8
|
"features/sign_in.feature",
|
9
9
|
"features/sign_out.feature",
|
10
|
-
"features/sign_up.feature"
|
10
|
+
"features/sign_up.feature",
|
11
|
+
"features/password_reset.feature"].each do |file|
|
11
12
|
m.file file, file
|
12
13
|
end
|
13
14
|
end
|
@@ -3,7 +3,7 @@ Fature: Password Reset
|
|
3
3
|
A user
|
4
4
|
Should be able to reset it
|
5
5
|
|
6
|
-
Scenario: User is not
|
6
|
+
Scenario: User is not signed up
|
7
7
|
Given there is no user with "email@person.com"
|
8
8
|
When I request password reset link to be sent to "email@person.com"
|
9
9
|
Then I should see "Unknown email"
|
@@ -1,9 +1,9 @@
|
|
1
1
|
Feature: Sign in
|
2
2
|
In order to get access to protected sections of the site
|
3
|
-
A
|
3
|
+
A user
|
4
4
|
Should be able to sign in
|
5
5
|
|
6
|
-
Scenario User is not
|
6
|
+
Scenario User is not signed up
|
7
7
|
Given there is no user with "email@person.com"
|
8
8
|
When I go to the sign in page
|
9
9
|
And I sign in as "email@person.com/password"
|
@@ -28,17 +28,14 @@ end
|
|
28
28
|
|
29
29
|
Then /^I should be signed in$/ do
|
30
30
|
assert_not_nil request.session[:user_id]
|
31
|
-
assert_not_nil request.session[:salt]
|
32
31
|
end
|
33
32
|
|
34
33
|
Then /^I should not be signed in$/ do
|
35
34
|
assert_nil request.session[:user_id]
|
36
|
-
assert_nil request.session[:salt]
|
37
35
|
end
|
38
36
|
|
39
37
|
When /^session is cleared$/ do
|
40
38
|
request.session[:user_id] = nil
|
41
|
-
request.session[:salt] = nil
|
42
39
|
end
|
43
40
|
|
44
41
|
# Emails
|
@@ -26,8 +26,8 @@ module Clearance
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def user_from_session
|
29
|
-
if session[:user_id]
|
30
|
-
user = User.
|
29
|
+
if session[:user_id]
|
30
|
+
user = User.find_by_id(session[:user_id])
|
31
31
|
user && user.email_confirmed? ? user : nil
|
32
32
|
end
|
33
33
|
end
|
@@ -47,7 +47,6 @@ module Clearance
|
|
47
47
|
def sign_in(user)
|
48
48
|
if user
|
49
49
|
session[:user_id] = user.id
|
50
|
-
session[:salt] = user.salt
|
51
50
|
end
|
52
51
|
end
|
53
52
|
|
@@ -66,7 +65,7 @@ module Clearance
|
|
66
65
|
end
|
67
66
|
|
68
67
|
def store_location
|
69
|
-
session[:return_to] = request.request_uri
|
68
|
+
session[:return_to] = request.request_uri if request.get?
|
70
69
|
end
|
71
70
|
|
72
71
|
def deny_access(flash_message = nil, opts = {})
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'digest/
|
1
|
+
require 'digest/sha1'
|
2
2
|
|
3
3
|
module Clearance
|
4
4
|
module App
|
@@ -17,10 +17,10 @@ module Clearance
|
|
17
17
|
validates_uniqueness_of :email, :case_sensitive => false
|
18
18
|
validates_format_of :email, :with => %r{.+@.+\..+}
|
19
19
|
|
20
|
-
before_save :initialize_salt, :encrypt_password, :initialize_token
|
20
|
+
before_save :initialize_salt, :encrypt_password, :initialize_token
|
21
21
|
|
22
22
|
def self.authenticate(email, password)
|
23
|
-
user = find(:first, :conditions => ['
|
23
|
+
user = find(:first, :conditions => ['email = ?', email.to_s])
|
24
24
|
user && user.authenticated?(password) ? user : nil
|
25
25
|
end
|
26
26
|
|
@@ -72,7 +72,7 @@ module Clearance
|
|
72
72
|
protected
|
73
73
|
|
74
74
|
def generate_hash(string)
|
75
|
-
Digest::
|
75
|
+
Digest::SHA1.hexdigest(string)
|
76
76
|
end
|
77
77
|
|
78
78
|
def initialize_salt
|
@@ -104,10 +104,6 @@ module Clearance
|
|
104
104
|
encrypted_password.blank? || !password.blank?
|
105
105
|
end
|
106
106
|
|
107
|
-
def downcase_email
|
108
|
-
self.email = email.to_s.downcase
|
109
|
-
end
|
110
|
-
|
111
107
|
end
|
112
108
|
end
|
113
109
|
|
@@ -11,13 +11,11 @@ module Clearance
|
|
11
11
|
user.confirm_email!
|
12
12
|
end
|
13
13
|
@request.session[:user_id] = user.id
|
14
|
-
@request.session[:salt] = user.salt
|
15
14
|
return user
|
16
15
|
end
|
17
16
|
|
18
17
|
def sign_out
|
19
18
|
@request.session[:user_id] = nil
|
20
|
-
@request.session[:salt] = nil
|
21
19
|
end
|
22
20
|
|
23
21
|
end
|
@@ -6,14 +6,14 @@ module Clearance
|
|
6
6
|
def self.included(unit_test)
|
7
7
|
unit_test.class_eval do
|
8
8
|
|
9
|
-
|
9
|
+
should_not_allow_mass_assignment_of :email_confirmed,
|
10
10
|
:salt, :encrypted_password,
|
11
11
|
:token, :token_expires_at
|
12
12
|
|
13
13
|
# signing up
|
14
14
|
|
15
15
|
context "When signing up" do
|
16
|
-
|
16
|
+
should_validate_presence_of :email, :password
|
17
17
|
should_allow_values_for :email, "foo@example.com"
|
18
18
|
should_not_allow_values_for :email, "foo"
|
19
19
|
should_not_allow_values_for :email, "example.com"
|
@@ -33,13 +33,13 @@ module Clearance
|
|
33
33
|
context "encrypt password" do
|
34
34
|
setup do
|
35
35
|
@salt = "salt"
|
36
|
-
|
37
|
-
|
38
|
-
@user
|
36
|
+
@user = Factory.build(:user, :salt => @salt)
|
37
|
+
def @user.initialize_salt; end
|
38
|
+
@user.save!
|
39
39
|
@password = @user.password
|
40
40
|
|
41
41
|
@user.encrypt(@password)
|
42
|
-
@expected = Digest::
|
42
|
+
@expected = Digest::SHA1.hexdigest("--#{@salt}--#{@password}--")
|
43
43
|
end
|
44
44
|
|
45
45
|
should "create an encrypted password using SHA512 encryption" do
|
@@ -48,16 +48,16 @@ module Clearance
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
should "store email in
|
51
|
+
should "store email in exact case" do
|
52
52
|
user = Factory(:user, :email => "John.Doe@example.com")
|
53
|
-
assert_equal "
|
53
|
+
assert_equal "John.Doe@example.com", user.email
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
57
|
context "When multiple users have signed up" do
|
58
58
|
setup { @user = Factory(:user) }
|
59
59
|
|
60
|
-
|
60
|
+
should_validate_uniqueness_of :email
|
61
61
|
end
|
62
62
|
|
63
63
|
# confirming email
|
@@ -97,11 +97,6 @@ module Clearance
|
|
97
97
|
assert @user.authenticated?(@password)
|
98
98
|
end
|
99
99
|
|
100
|
-
should "authenticate with good credentials, email in uppercase" do
|
101
|
-
assert User.authenticate(@user.email.upcase, @password)
|
102
|
-
assert @user.authenticated?(@password)
|
103
|
-
end
|
104
|
-
|
105
100
|
should "not authenticate with bad credentials" do
|
106
101
|
assert ! User.authenticate(@user.email, 'horribly_wrong_password')
|
107
102
|
assert ! @user.authenticated?('horribly_wrong_password')
|
@@ -185,6 +180,7 @@ module Clearance
|
|
185
180
|
assert_nil @user.token
|
186
181
|
@user.forgot_password!
|
187
182
|
end
|
183
|
+
|
188
184
|
should "generate token" do
|
189
185
|
assert_not_nil @user.token
|
190
186
|
end
|
@@ -199,17 +195,20 @@ module Clearance
|
|
199
195
|
end
|
200
196
|
|
201
197
|
should_change "@user.encrypted_password"
|
198
|
+
|
202
199
|
should "clear token" do
|
203
200
|
assert_nil @user.token
|
204
201
|
end
|
205
202
|
end
|
203
|
+
|
206
204
|
context 'with a password without a confirmation' do
|
207
205
|
setup do
|
208
206
|
@user.update_password(
|
209
207
|
:password => "new_password",
|
210
208
|
:password_confirmation => ""
|
211
209
|
)
|
212
|
-
end
|
210
|
+
end
|
211
|
+
|
213
212
|
should "not clear token" do
|
214
213
|
assert_not_nil @user.token
|
215
214
|
end
|
data/shoulda_macros/clearance.rb
CHANGED
@@ -10,8 +10,6 @@ module Clearance
|
|
10
10
|
"please pass a User. try: should_be_signed_in_as { @user }"
|
11
11
|
assert_equal user.id, session[:user_id],
|
12
12
|
"session[:user_id] is not set to User's id"
|
13
|
-
assert_equal user.salt, session[:salt],
|
14
|
-
"session[:salt] is not set to User's salt"
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
@@ -30,7 +28,6 @@ module Clearance
|
|
30
28
|
def should_not_be_signed_in
|
31
29
|
should "not be signed in" do
|
32
30
|
assert_nil session[:user_id]
|
33
|
-
assert_nil session[:salt]
|
34
31
|
end
|
35
32
|
end
|
36
33
|
|
@@ -167,7 +164,6 @@ module Clearance
|
|
167
164
|
end
|
168
165
|
end
|
169
166
|
|
170
|
-
|
171
167
|
# FORMS
|
172
168
|
|
173
169
|
def should_display_a_password_update_form
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thoughtbot-clearance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thoughtbot, inc.
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2009-02-
|
18
|
+
date: 2009-02-08 21:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -32,7 +32,6 @@ files:
|
|
32
32
|
- LICENSE
|
33
33
|
- Rakefile
|
34
34
|
- README.textile
|
35
|
-
- TODO.textile
|
36
35
|
- generators/clearance
|
37
36
|
- generators/clearance/clearance_generator.rb
|
38
37
|
- generators/clearance/lib
|
data/TODO.textile
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
(highest priority first)
|
2
|
-
|
3
|
-
# refactor password controller test
|
4
|
-
# existing_user? methods ... if salt is wrong, user may not be found b/c of invalid credentials. is :not_found the correct code to return in that use case? if not, method probably needs to be split into another conditional.
|
5
|
-
# document shoulda macros
|
6
|
-
# will SHA512 hashes fit in all the places they are being used? (db columns - fit now, sessions) 128 characters
|
7
|
-
|
8
|
-
http://adam.speaksoutofturn.com/post/57615195/entication-vs-orization
|