mbleigh-twitter-auth 0.1.8 → 0.1.10

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/README.markdown CHANGED
@@ -76,6 +76,10 @@ TwitterAuth provides some default controller methods that may be overridden in y
76
76
  * `authentication_succeeded(message=default)`: called when Twitter authorization has completed successfully. By default, simply redirects to the site root and sets the `flash[:notice]`.
77
77
  * `access_denied`: what happens when the `login_required` before filter fails. By default it stores the current location to return to and redirects to the login process.
78
78
 
79
+ Resources
80
+ ---------
81
+
82
+ * **Bug Reports:** See the [Lighthouse Project](http://mbleigh.lighthouseapp.com/projects/27783-twitterauth) to report any problems you have using TwitterAuth.
79
83
 
80
84
  Copyright
81
85
  ---------
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :minor: 1
3
- :patch: 8
3
+ :patch: 10
4
4
  :major: 0
@@ -45,6 +45,8 @@ class SessionsController < ApplicationController
45
45
 
46
46
  session[:user_id] = @user.id
47
47
 
48
+ cookies[:remember_token] = @user.remember_me
49
+
48
50
  authentication_succeeded
49
51
  rescue Net::HTTPServerException => e
50
52
  case e.message
@@ -1,7 +1,7 @@
1
1
  module TwitterAuth
2
2
  class GenericUser < ActiveRecord::Base
3
- attr_protected :login
4
-
3
+ attr_protected :login, :remember_token, :remember_token_expires_at
4
+
5
5
  TWITTER_ATTRIBUTES = [
6
6
  :name,
7
7
  :location,
@@ -26,6 +26,7 @@ module TwitterAuth
26
26
  validates_format_of :login, :with => /\A[a-z0-9_]+\z/i
27
27
  validates_length_of :login, :in => 1..15
28
28
  validates_uniqueness_of :login, :case_sensitive => false
29
+ validates_uniqueness_of :remember_token, :allow_blank => true
29
30
 
30
31
  def self.table_name; 'users' end
31
32
 
@@ -41,6 +42,10 @@ module TwitterAuth
41
42
 
42
43
  user
43
44
  end
45
+
46
+ def self.from_remember_token(token)
47
+ first(:conditions => ["remember_token = ? AND remember_token_expires_at > ?", token, Time.now])
48
+ end
44
49
 
45
50
  def assign_twitter_attributes(hash)
46
51
  TWITTER_ATTRIBUTES.each do |att|
@@ -66,5 +71,21 @@ module TwitterAuth
66
71
  TwitterAuth::Dispatcher::Basic.new(self)
67
72
  end
68
73
  end
74
+
75
+ def remember_me
76
+ return false unless respond_to?(:remember_token)
77
+
78
+ self.remember_token = ActiveSupport::SecureRandom.hex(10)
79
+ self.remember_token_expires_at = Time.now + TwitterAuth.remember_for.days
80
+
81
+ save
82
+
83
+ {:value => self.remember_token, :expires => self.remember_token_expires_at}
84
+ end
85
+
86
+ def forget_me
87
+ self.remember_token = self.remember_token_expires_at = nil
88
+ self.save
89
+ end
69
90
  end
70
91
  end
@@ -10,6 +10,9 @@ class TwitterAuthMigration < ActiveRecord::Migration
10
10
  t.string :salt
11
11
  <% end -%>
12
12
 
13
+ t.string :remember_token
14
+ t.datetime :remember_token_expires_at
15
+
13
16
  # This information is automatically kept
14
17
  # in-sync at each login of the user. You
15
18
  # may remove any/all of these columns.
@@ -1,24 +1,27 @@
1
1
  <% if options[:oauth] -%>
2
2
  development:
3
3
  strategy: oauth
4
- base_url: "https://twitter.com"
5
- api_timeout: 10
6
4
  oauth_consumer_key: devkey
7
5
  oauth_consumer_secret: devsecret
6
+ base_url: "https://twitter.com"
7
+ api_timeout: 10
8
+ remember_for: 14 # days
8
9
  oauth_callback: "http://localhost:3000/oauth_callback"
9
10
  test:
10
11
  strategy: oauth
11
- base_url: "https://twitter.com"
12
- api_timeout: 10
13
12
  oauth_consumer_key: testkey
14
13
  oauth_consumer_secret: testsecret
14
+ base_url: "https://twitter.com"
15
+ api_timeout: 10
16
+ remember_for: 14 # days
15
17
  oauth_callback: "http://localhost:3000/oauth_callback"
16
18
  production:
17
19
  strategy: oauth
18
- api_timeout: 10
19
- base_url: "https://twitter.com"
20
20
  oauth_consumer_key: prodkey
21
21
  oauth_consumer_secret: prodsecret
22
+ base_url: "https://twitter.com"
23
+ api_timeout: 10
24
+ remember_for: 14 # days
22
25
  <% else -%>
23
26
  development:
24
27
  strategy: basic
@@ -26,13 +29,16 @@ development:
26
29
  base_url: "https://twitter.com"
27
30
  # randomly generated key for encrypting Twitter passwords
28
31
  encryption_key: "<%= key = ActiveSupport::SecureRandom.hex(12) %>"
32
+ remember_for: 14 # days
29
33
  test:
30
34
  strategy: basic
31
35
  api_timeout: 10
32
36
  base_url: "https://twitter.com"
33
37
  encryption_key: "<%= key %>"
38
+ remember_for: 14 # days
34
39
  production:
35
40
  strategy: basic
36
41
  api_timeout: 10
37
42
  encryption_key: "<%= key %>"
43
+ remember_for: 14 # days
38
44
  <% end %>
@@ -20,7 +20,7 @@ module TwitterAuth
20
20
  end
21
21
 
22
22
  def current_user
23
- @current_user ||= User.find_by_id(session[:user_id])
23
+ @current_user ||= User.find_by_id(session[:user_id]) || User.from_remember_token(cookies[:remember_token])
24
24
  end
25
25
 
26
26
  def current_user=(new_user)
@@ -57,6 +57,7 @@ module TwitterAuth
57
57
  def logout_keeping_session!
58
58
  @current_user = nil
59
59
  session[:user_id] = nil
60
+ cookies.delete(:remember_token)
60
61
  end
61
62
  end
62
63
  end
data/lib/twitter_auth.rb CHANGED
@@ -27,6 +27,10 @@ module TwitterAuth
27
27
  config['oauth_callback']
28
28
  end
29
29
 
30
+ def self.remember_for
31
+ (config['remember_for'] || 14).to_i
32
+ end
33
+
30
34
  # The authentication strategy employed by this
31
35
  # application. Set in +config/twitter.yml+ as
32
36
  # strategy; valid options are oauth or basic.
@@ -35,9 +35,18 @@ class TwitterAuthTestController < ApplicationController
35
35
  logout_keeping_session!
36
36
  redirect_back_or_default('/')
37
37
  end
38
+
39
+ def current_user_action
40
+ @user = current_user
41
+ render :nothing => true
42
+ end
38
43
  end
39
44
 
40
45
  describe TwitterAuthTestController do
46
+ before do
47
+ controller.stub!(:cookies).and_return({})
48
+ end
49
+
41
50
  %w(authentication_failed authentication_succeeded current_user authorized? login_required access_denied store_location redirect_back_or_default logout_keeping_session!).each do |m|
42
51
  it "should respond to the extension method '#{m}'" do
43
52
  controller.should respond_to(m)
@@ -72,19 +81,21 @@ describe TwitterAuthTestController do
72
81
  it 'should find the user based on the session user_id' do
73
82
  user = Factory.create(:twitter_oauth_user)
74
83
  request.session[:user_id] = user.id
75
- controller.send(:current_user).should == user
84
+ get(:current_user_action)
85
+ assigns[:user].should == user
76
86
  end
77
87
 
78
- it 'should return nil if there is no user matching that id' do
79
- request.session[:user_id] = 2345
80
- controller.send(:current_user).should be_nil
88
+ it 'should log the user in through a cookie' do
89
+ user = Factory(:twitter_oauth_user, :remember_token => 'abc', :remember_token_expires_at => (Time.now + 10.days))
90
+ controller.stub!(:cookies).and_return({:remember_token => 'abc'})
91
+ get :current_user_action
92
+ assigns[:user].should == user
81
93
  end
82
94
 
83
- it 'should memoize the result (and not do a double find)' do
84
- user = Factory.create(:twitter_oauth_user)
85
- User.should_receive(:find_by_id).once.and_return(user)
86
- controller.send(:current_user).should == user
87
- controller.send(:current_user).should == user
95
+ it 'should return nil if there is no user matching that id' do
96
+ request.session[:user_id] = 2345
97
+ get :current_user_action
98
+ assigns[:user].should be_nil
88
99
  end
89
100
  end
90
101
 
@@ -142,5 +153,10 @@ describe TwitterAuthTestController do
142
153
  get :logout_keeping_session_action
143
154
  controller.send(:current_user).should be_nil
144
155
  end
156
+
157
+ it 'should unset the cookie' do
158
+ controller.send(:cookies).should_receive(:delete).with(:remember_token)
159
+ get :logout_keeping_session_action
160
+ end
145
161
  end
146
162
  end
@@ -82,6 +82,12 @@ describe SessionsController do
82
82
  describe 'with proper info' do
83
83
  before do
84
84
  @user = Factory.create(:twitter_oauth_user)
85
+ @time = Time.now
86
+ @remember_token = ActiveSupport::SecureRandom.hex(10)
87
+
88
+ Time.stub!(:now).and_return(@time)
89
+ ActiveSupport::SecureRandom.stub!(:hex).and_return(@remember_token)
90
+
85
91
  request.session[:request_token] = 'faketoken'
86
92
  request.session[:request_token_secret] = 'faketokensecret'
87
93
  get :oauth_callback, :oauth_token => 'faketoken'
@@ -116,6 +122,15 @@ describe SessionsController do
116
122
  it "should assign the user id to the session" do
117
123
  session[:user_id].should == @user.id
118
124
  end
125
+
126
+ it "should call remember me" do
127
+ @user.reload
128
+ @user.remember_token.should == @remember_token
129
+ end
130
+
131
+ it "should set a cookie" do
132
+ cookies[:remember_token].should == @remember_token
133
+ end
119
134
  end
120
135
 
121
136
  describe "when OAuth doesn't work" do
@@ -5,12 +5,17 @@ describe TwitterAuth::GenericUser do
5
5
  should_validate_format_of :login, 'some_guy', 'awesome', 'cool_man'
6
6
  should_not_validate_format_of :login, 'with-dashes', 'with.periods', 'with spaces'
7
7
  should_validate_length_of :login, :in => 1..15
8
-
8
+
9
9
  it 'should validate uniqueness of login' do
10
10
  Factory.create(:twitter_oauth_user)
11
11
  Factory.build(:twitter_oauth_user).should have_at_least(1).errors_on(:login)
12
12
  end
13
13
 
14
+ it 'should validate uniqueness of remember_token' do
15
+ Factory.create(:twitter_oauth_user, :remember_token => 'abc')
16
+ Factory.build(:twitter_oauth_user, :remember_token => 'abc').should have_at_least(1).errors_on(:remember_token)
17
+ end
18
+
14
19
  it 'should allow capital letters in the username' do
15
20
  Factory.build(:twitter_oauth_user, :login => 'TwitterMan').should have(:no).errors_on(:login)
16
21
  end
@@ -54,4 +59,84 @@ describe TwitterAuth::GenericUser do
54
59
  lambda{user.update_twitter_attributes({'name' => 'Twitter Man', 'description' => 'Works.', 'whoopsy' => 'noworks.'})}.should_not raise_error
55
60
  end
56
61
  end
62
+
63
+ describe '#remember_me' do
64
+ before do
65
+ @user = Factory(:twitter_oauth_user)
66
+ end
67
+
68
+ it 'should check for the remember_token column' do
69
+ @user.should_receive(:respond_to?).with(:remember_token).and_return(false)
70
+ @user.remember_me
71
+ end
72
+
73
+ it 'should return nil if there is no remember_token column' do
74
+ @user.should_receive(:respond_to?).with(:remember_token).and_return(false)
75
+ @user.remember_me.should be_false
76
+ end
77
+
78
+ describe ' with proper columns' do
79
+ it 'should generate a secure random token' do
80
+ ActiveSupport::SecureRandom.should_receive(:hex).with(10).and_return('abcdef')
81
+ @user.remember_me
82
+ @user.remember_token.should == 'abcdef'
83
+ end
84
+
85
+ it 'should set the expiration to the current time plus the remember_for period' do
86
+ TwitterAuth.stub!(:remember_for).and_return(10)
87
+ time = Time.now
88
+ Time.stub!(:now).and_return(time)
89
+
90
+ @user.remember_me
91
+
92
+ @user.remember_token_expires_at.should == Time.now + 10.days
93
+ end
94
+
95
+ it 'should return a hash with a :value and :expires key' do
96
+ result = @user.remember_me
97
+ result.should be_a(Hash)
98
+ result.key?(:value).should be_true
99
+ result.key?(:expires).should be_true
100
+ end
101
+
102
+ it 'should return a hash with appropriate values' do
103
+ TwitterAuth.stub!(:remember_for).and_return(10)
104
+ time = Time.now
105
+ Time.stub!(:now).and_return(time)
106
+ ActiveSupport::SecureRandom.stub!(:hex).and_return('abcdef')
107
+
108
+ @user.remember_me.should == {:value => 'abcdef', :expires => (Time.now + 10.days)}
109
+ end
110
+ end
111
+ end
112
+
113
+ describe '#forget_me' do
114
+ it 'should reset remember_token and remember_token_expires_at' do
115
+ @user = Factory(:twitter_oauth_user, :remember_token => "abcdef", :remember_token_expires_at => Time.now + 10.days)
116
+ @user.forget_me
117
+ @user.reload
118
+ @user.remember_token.should be_nil
119
+ @user.remember_token_expires_at.should be_nil
120
+ end
121
+ end
122
+
123
+ describe '.from_remember_token' do
124
+ before do
125
+ @user = Factory(:twitter_oauth_user, :remember_token => 'abcdef', :remember_token_expires_at => (Time.now + 10.days))
126
+ end
127
+
128
+ it 'should find the user with the specified remember_token' do
129
+ User.from_remember_token('abcdef').should == @user
130
+ end
131
+
132
+ it 'should not find a user with an expired token' do
133
+ user2 = Factory(:twitter_oauth_user, :login => 'walker', :remember_token => 'ghijkl', :remember_token_expires_at => (Time.now - 10.days))
134
+ User.from_remember_token('ghijkl').should be_nil
135
+ end
136
+
137
+ it 'should not find a user with a nil token and an expiration' do
138
+ user = Factory(:twitter_oauth_user, :login => 'stranger', :remember_token => nil, :remember_token_expires_at => (Time.now + 10.days))
139
+ User.from_remember_token(nil).should be_nil
140
+ end
141
+ end
57
142
  end
data/spec/schema.rb CHANGED
@@ -10,6 +10,10 @@ ActiveRecord::Schema.define :version => 0 do
10
10
  t.binary :crypted_password
11
11
  t.string :salt
12
12
 
13
+ # Remember token fields
14
+ t.string :remember_token
15
+ t.datetime :remember_token_expires_at
16
+
13
17
  # This information is automatically kept
14
18
  # in-sync at each login of the user. You
15
19
  # may remove any/all of these columns.
@@ -13,7 +13,7 @@ describe TwitterAuth do
13
13
  end
14
14
  end
15
15
 
16
- describe '#api_timeout' do
16
+ describe '.api_timeout' do
17
17
  it 'should default to 10' do
18
18
  TwitterAuth.stub!(:config).and_return({})
19
19
  TwitterAuth.api_timeout.should == 10
@@ -25,6 +25,18 @@ describe TwitterAuth do
25
25
  end
26
26
  end
27
27
 
28
+ describe '.remember_for' do
29
+ it 'should default to 14' do
30
+ TwitterAuth.stub!(:config).and_return({})
31
+ TwitterAuth.remember_for.should == 14
32
+ end
33
+
34
+ it 'should be settable via config' do
35
+ TwitterAuth.stub!(:config).and_return({'remember_for' => '7'})
36
+ TwitterAuth.remember_for.should == 7
37
+ end
38
+ end
39
+
28
40
  describe '.net' do
29
41
  before do
30
42
  stub_basic!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mbleigh-twitter-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh