mbleigh-twitter-auth 0.0.2 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ development:
2
+ strategy: oauth
3
+ base_url: "https://twitter.com"
4
+ oauth_consumer_key: devkey
5
+ oauth_consumer_secret: devsecret
6
+ oauth_callback: "http://localhost:3000"
7
+ test:
8
+ strategy: oauth
9
+ base_url: "https://twitter.com"
10
+ oauth_consumer_key: testkey
11
+ oauth_consumer_secret: testsecret
12
+ production:
13
+ strategy: oauth
14
+ base_url: "https://twitter.com"
15
+ oauth_consumer_key: prodkey
16
+ oauth_consumer_secret: prodsecret
17
+
@@ -0,0 +1,18 @@
1
+ require 'factory_girl'
2
+
3
+ Factory.define(:twitter_oauth_user, :class => User) do |u|
4
+ u.login 'twitterman'
5
+ u.access_token 'fakeaccesstoken'
6
+ u.access_secret 'fakeaccesstokensecret'
7
+
8
+ u.name 'Twitter Man'
9
+ u.description 'Saving the world for all Twitter kind.'
10
+ end
11
+
12
+ Factory.define(:twitter_basic_user, :class => User) do |u|
13
+ u.login 'twitterman'
14
+ u.password 'test'
15
+
16
+ u.name 'Twitter Man'
17
+ u.description 'Saving the world for all Twitter kind.'
18
+ end
@@ -0,0 +1,18 @@
1
+ # This is where we fake out all of the URLs that we
2
+ # will be calling as a part of this spec suite.
3
+ # You must have the 'fakeweb' gem in order to run
4
+ # the tests for TwitterAuth.
5
+ #
6
+ # gem install 'mbleigh-fakeweb'
7
+
8
+ require 'fake_web'
9
+
10
+ FakeWeb.allow_net_connect = false
11
+
12
+ FakeWeb.register_uri(:post, 'https://twitter.com:443/oauth/request_token', :string => 'oauth_token=faketoken&oauth_token_secret=faketokensecret')
13
+
14
+ FakeWeb.register_uri(:post, 'https://twitter.com:443/oauth/access_token', :string => 'oauth_token=fakeaccesstoken&oauth_token_secret=fakeaccesstokensecret')
15
+
16
+ FakeWeb.register_uri(:get, 'https://twitter.com:443/account/verify_credentials.json', :string => "{\"profile_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/default_profile_normal.png\",\"description\":\"Saving the world for all Twitter kind.\",\"utc_offset\":null,\"favourites_count\":0,\"profile_sidebar_fill_color\":\"e0ff92\",\"screen_name\":\"twitterman\",\"statuses_count\":0,\"profile_background_tile\":false,\"profile_sidebar_border_color\":\"87bc44\",\"friends_count\":2,\"url\":null,\"name\":\"Twitter Man\",\"time_zone\":null,\"protected\":false,\"profile_background_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/themes\\/theme1\\/bg.gif\",\"profile_background_color\":\"9ae4e8\",\"created_at\":\"Fri Feb 06 18:10:32 +0000 2009\",\"profile_text_color\":\"000000\",\"followers_count\":2,\"location\":null,\"id\":20256865,\"profile_link_color\":\"0000ff\"}")
17
+
18
+ #FakeWeb.register_uri(:get, 'https://twitter.com:443/)
@@ -0,0 +1,5 @@
1
+ require 'net/http'
2
+
3
+ TWITTER_JSON = {
4
+ :verify_credentials => "{\"profile_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/default_profile_normal.png\",\"description\":\"Saving the world for all Twitter kind.\",\"utc_offset\":null,\"favourites_count\":0,\"profile_sidebar_fill_color\":\"e0ff92\",\"screen_name\":\"twitterman\",\"statuses_count\":0,\"profile_background_tile\":false,\"profile_sidebar_border_color\":\"87bc44\",\"friends_count\":2,\"url\":null,\"name\":\"Twitter Man\",\"time_zone\":null,\"protected\":false,\"profile_background_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/themes\\/theme1\\/bg.gif\",\"profile_background_color\":\"9ae4e8\",\"created_at\":\"Fri Feb 06 18:10:32 +0000 2009\",\"profile_text_color\":\"000000\",\"followers_count\":2,\"location\":null,\"id\":20256865,\"profile_link_color\":\"0000ff\"}"
5
+ }
@@ -0,0 +1,122 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe TwitterAuth::BasicUser do
4
+ before do
5
+ stub_basic!
6
+ end
7
+
8
+ describe '#password=' do
9
+ before do
10
+ @user = Factory.build(:twitter_basic_user)
11
+ end
12
+
13
+ it 'should change the value of crypted_password' do
14
+ lambda{@user.password = 'newpass'}.should change(@user, :crypted_password)
15
+ end
16
+
17
+ it 'should change the value of salt' do
18
+ lambda{@user.password = 'newpass'}.should change(@user, :salt)
19
+ end
20
+
21
+ it 'should not store the plaintext password' do
22
+ @user.password = 'newpass'
23
+ @user.crypted_password.should_not == 'newpass'
24
+ end
25
+ end
26
+
27
+ describe '#password' do
28
+ before do
29
+ @user = Factory.build(:twitter_basic_user, :password => 'monkey')
30
+ end
31
+
32
+ it 'should return the password' do
33
+ @user.password.should == 'monkey'
34
+ end
35
+
36
+ it 'should not be a database attribute' do
37
+ @user['password'].should_not == 'monkey'
38
+ end
39
+ end
40
+
41
+ describe '.verify_credentials' do
42
+ before do
43
+ @user = Factory.create(:twitter_basic_user)
44
+ end
45
+
46
+ it 'should return a JSON hash of the user when successful' do
47
+ hash = User.verify_credentials('twitterman','test')
48
+ hash.should be_a(Hash)
49
+ hash['screen_name'].should == 'twitterman'
50
+ hash['name'].should == 'Twitter Man'
51
+ end
52
+
53
+ it 'should return false when a 401 unauthorized happens' do
54
+ FakeWeb.register_uri(:get, 'https://twitter.com:443/account/verify_credentials.json', :string => '401 "Unauthorized"', :status => ['401',' Unauthorized'])
55
+ User.verify_credentials('twitterman','wrong').should be_false
56
+ end
57
+ end
58
+
59
+ describe '.authenticate' do
60
+ before do
61
+ @user = Factory.create(:twitter_basic_user)
62
+ end
63
+
64
+ it 'should make a call to verify_credentials' do
65
+ User.should_receive(:verify_credentials).with('twitterman','test')
66
+ User.authenticate('twitterman','test')
67
+ end
68
+
69
+ it 'should return nil if verify_credentials returns false' do
70
+ User.stub!(:verify_credentials).and_return(false)
71
+ User.authenticate('twitterman','test').should be_nil
72
+ end
73
+
74
+ it 'should return the user if verify_credentials succeeds' do
75
+ User.stub!(:verify_credentials).and_return(JSON.parse("{\"profile_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/default_profile_normal.png\",\"description\":\"Saving the world for all Twitter kind.\",\"utc_offset\":null,\"favourites_count\":0,\"profile_sidebar_fill_color\":\"e0ff92\",\"screen_name\":\"twitterman\",\"statuses_count\":0,\"profile_background_tile\":false,\"profile_sidebar_border_color\":\"87bc44\",\"friends_count\":2,\"url\":null,\"name\":\"Twitter Man\",\"time_zone\":null,\"protected\":false,\"profile_background_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/themes\\/theme1\\/bg.gif\",\"profile_background_color\":\"9ae4e8\",\"created_at\":\"Fri Feb 06 18:10:32 +0000 2009\",\"profile_text_color\":\"000000\",\"followers_count\":2,\"location\":null,\"id\":20256865,\"profile_link_color\":\"0000ff\"}"))
76
+ User.authenticate('twitterman','test').should == @user
77
+ end
78
+ end
79
+
80
+ describe '.find_or_create_by_twitter_hash_and_password' do
81
+ before do
82
+ @user = Factory.create(:twitter_basic_user)
83
+ end
84
+
85
+ it 'should return the existing user if there is one' do
86
+ User.identify_or_create_from_twitter_hash_and_password({'screen_name' => 'twitterman'},'test').should == @user
87
+ end
88
+
89
+ it 'should update the attributes from the hash' do
90
+ User.identify_or_create_from_twitter_hash_and_password({'screen_name' => 'twitterman', 'name' => 'New Name'}, 'test').name.should == 'New Name'
91
+ end
92
+
93
+ it 'should update the password from the argument' do
94
+ User.identify_or_create_from_twitter_hash_and_password({'screen_name' => 'twitterman', 'name' => 'New Name'}, 'test2').password.should == 'test2'
95
+ end
96
+
97
+ it 'should create a user if one does not exist' do
98
+ lambda{User.identify_or_create_from_twitter_hash_and_password({'screen_name' => 'dude', 'name' => "Lebowski"}, 'test')}.should change(User, :count).by(1)
99
+ end
100
+
101
+ it 'should assign the attributes from the hash to a created user' do
102
+ user = User.identify_or_create_from_twitter_hash_and_password({'screen_name' => 'dude', 'name' => "Lebowski"}, 'test')
103
+ user.login.should == 'dude'
104
+ user.name.should == 'Lebowski'
105
+ user.password.should == 'test'
106
+ end
107
+ end
108
+
109
+ describe '#twitter' do
110
+ before do
111
+ @user = Factory.create(:twitter_basic_user)
112
+ end
113
+
114
+ it 'should be an instance of TwitterAuth::Dispatcher::Basic' do
115
+ @user.twitter.class.should == TwitterAuth::Dispatcher::Basic
116
+ end
117
+
118
+ it 'should have the correct user set' do
119
+ @user.twitter.user.should == @user
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe TwitterAuth::GenericUser do
4
+ should_validate_presence_of :login
5
+ should_validate_format_of :login, 'some_guy', 'awesome', 'cool_man'
6
+ should_not_validate_format_of :login, 'with-dashes', 'with.periods', 'with spaces'
7
+ should_validate_length_of :login, :in => 1..15
8
+
9
+ it 'should validate uniqueness of login' do
10
+ Factory.create(:twitter_oauth_user)
11
+ Factory.build(:twitter_oauth_user).should have_at_least(1).errors_on(:login)
12
+ end
13
+
14
+ describe '.new_from_twitter_hash' do
15
+ it 'should raise an argument error if the hash does not have a screen_name attribute' do
16
+ lambda{User.new_from_twitter_hash({})}.should raise_error(ArgumentError, 'Invalid hash: must include screen_name.')
17
+ end
18
+
19
+ it 'should return a user' do
20
+ User.new_from_twitter_hash({'screen_name' => 'twitterman'}).should be_a(User)
21
+ end
22
+
23
+ it 'should assign login to the screen_name' do
24
+ User.new_from_twitter_hash({'screen_name' => 'twitterman'}).login.should == 'twitterman'
25
+ end
26
+
27
+ it 'should assign twitter attributes that are provided' do
28
+ u = User.new_from_twitter_hash({'screen_name' => 'twitterman', 'name' => 'Twitter Man', 'description' => 'Saving the world for all Tweet kind.'})
29
+ u.name.should == 'Twitter Man'
30
+ u.description.should == 'Saving the world for all Tweet kind.'
31
+ end
32
+ end
33
+
34
+ describe '#update_twitter_attributes' do
35
+ it 'should assign values to the user' do
36
+ user = Factory.create(:twitter_oauth_user, :name => "Dude", :description => "Awesome, man.")
37
+ user.update_twitter_attributes({'name' => 'Twitter Man', 'description' => 'Works.'})
38
+ user.reload
39
+ user.name.should == 'Twitter Man'
40
+ user.description.should == 'Works.'
41
+ end
42
+
43
+ it 'should not throw an error with extraneous info' do
44
+ user = Factory.create(:twitter_oauth_user, :name => "Dude", :description => "Awesome, man.")
45
+ lambda{user.update_twitter_attributes({'name' => 'Twitter Man', 'description' => 'Works.', 'whoopsy' => 'noworks.'})}.should_not raise_error
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,85 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe TwitterAuth::OauthUser do
4
+ before do
5
+ stub_oauth!
6
+ end
7
+
8
+ describe '.identify_or_create_from_access_token' do
9
+ before do
10
+ @token = OAuth::AccessToken.new(TwitterAuth.consumer, 'faketoken', 'fakesecret')
11
+ end
12
+
13
+ it 'should accept an OAuth::AccessToken' do
14
+ lambda{ User.identify_or_create_from_access_token(@token) }.should_not raise_error(ArgumentError)
15
+ end
16
+
17
+ it 'should accept two strings' do
18
+ lambda{ User.identify_or_create_from_access_token('faketoken', 'fakesecret') }.should_not raise_error(ArgumentError)
19
+ end
20
+
21
+ it 'should not accept one string' do
22
+ lambda{ User.identify_or_create_from_access_token('faketoken') }.should raise_error(ArgumentError, 'Must authenticate with an OAuth::AccessToken or the string access token and secret.')
23
+ end
24
+
25
+ it 'should make a call to verify_credentials' do
26
+ # this is in the before, just making it explicit
27
+ User.identify_or_create_from_access_token(@token)
28
+ end
29
+
30
+ it 'should try to find the user with that login' do
31
+ User.should_receive(:find_by_login).once.with('twitterman')
32
+ User.identify_or_create_from_access_token(@token)
33
+ end
34
+
35
+ it 'should return the user if he/she exists' do
36
+ user = Factory.create(:twitter_oauth_user, :login => 'twitterman')
37
+ User.identify_or_create_from_access_token(@token).should == user
38
+ end
39
+
40
+ it 'should update the user\'s attributes based on the twitter info' do
41
+ user = Factory.create(:twitter_oauth_user, :login => 'twitterman', :name => 'Not Twitter Man')
42
+ User.identify_or_create_from_access_token(@token).name.should == 'Twitter Man'
43
+ end
44
+
45
+ it 'should create a user if one does not exist' do
46
+ lambda{User.identify_or_create_from_access_token(@token)}.should change(User, :count).by(1)
47
+ end
48
+
49
+ it 'should assign the oauth access token and secret' do
50
+ user = User.identify_or_create_from_access_token(@token)
51
+ user.access_token.should == @token.token
52
+ user.access_secret.should == @token.secret
53
+ end
54
+ end
55
+
56
+ describe '#token' do
57
+ before do
58
+ @user = Factory.create(:twitter_oauth_user, :access_token => 'token', :access_secret => 'secret')
59
+ end
60
+
61
+ it 'should return an AccessToken' do
62
+ @user.token.should be_a(OAuth::AccessToken)
63
+ end
64
+
65
+ it "should use the user's access_token and secret" do
66
+ @user.token.token.should == @user.access_token
67
+ @user.token.secret.should == @user.access_secret
68
+ end
69
+ end
70
+
71
+ describe '#twitter' do
72
+ before do
73
+ @user = Factory.create(:twitter_oauth_user, :access_token => 'token', :access_secret => 'secret')
74
+ end
75
+
76
+ it 'should return a TwitterAuth::Dispatcher::Oauth' do
77
+ @user.twitter.should be_a(TwitterAuth::Dispatcher::Oauth)
78
+ end
79
+
80
+ it 'should use my token and secret' do
81
+ @user.twitter.token.should == @user.access_token
82
+ @user.twitter.secret.should == @user.access_secret
83
+ end
84
+ end
85
+ end
data/spec/schema.rb ADDED
@@ -0,0 +1,37 @@
1
+ ActiveRecord::Schema.define :version => 0 do
2
+ create_table :twitter_auth_users, :force => true do |t|
3
+ t.string :login
4
+
5
+ # OAuth fields
6
+ t.string :access_token
7
+ t.string :access_secret
8
+
9
+ # Basic fields
10
+ t.binary :crypted_password
11
+ t.string :salt
12
+
13
+ # This information is automatically kept
14
+ # in-sync at each login of the user. You
15
+ # may remove any/all of these columns.
16
+ t.string :name
17
+ t.string :location
18
+ t.string :description
19
+ t.string :profile_image_url
20
+ t.string :url
21
+ t.boolean :protected
22
+ t.string :profile_background_color
23
+ t.string :profile_sidebar_fill_color
24
+ t.string :profile_link_color
25
+ t.string :profile_sidebar_border_color
26
+ t.string :profile_text_color
27
+ t.integer :friends_count
28
+ t.integer :statuses_count
29
+ t.integer :followers_count
30
+ t.integer :favourites_count
31
+ t.integer :utc_offset
32
+ t.string :time_zone
33
+
34
+ t.timestamps
35
+ end
36
+ end
37
+
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
data/spec/spec_helper.rb CHANGED
@@ -5,6 +5,47 @@ rescue LoadError
5
5
  exit
6
6
  end
7
7
 
8
+ require File.dirname(__FILE__) + '/../app/models/twitter_auth/generic_user'
9
+
10
+ class TwitterAuth::GenericUser
11
+ def self.table_name; 'twitter_auth_users' end
12
+ end
13
+
14
+ class User < TwitterAuth::GenericUser; end
15
+
16
+ require 'remarkable'
17
+ require File.dirname(__FILE__) + '/fixtures/factories'
18
+ require File.dirname(__FILE__) + '/fixtures/fakeweb'
19
+ require File.dirname(__FILE__) + '/fixtures/twitter'
20
+
8
21
  plugin_spec_dir = File.dirname(__FILE__)
9
22
  ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log")
10
23
 
24
+ load(File.dirname(__FILE__) + '/schema.rb')
25
+
26
+ def define_basic_user_class!
27
+ TwitterAuth::GenericUser.send :include, TwitterAuth::BasicUser
28
+ end
29
+
30
+ def define_oauth_user_class!
31
+ TwitterAuth::GenericUser.send :include, TwitterAuth::OauthUser
32
+ end
33
+
34
+ def stub_oauth!
35
+ TwitterAuth.stub!(:config).and_return({
36
+ 'strategy' => 'oauth',
37
+ 'oauth_consumer_key' => 'testkey',
38
+ 'oauth_consumer_secret' => 'testsecret'
39
+ })
40
+ define_oauth_user_class!
41
+ end
42
+
43
+ def stub_basic!
44
+ TwitterAuth.stub!(:config).and_return({
45
+ 'strategy' => 'basic',
46
+ 'encryption_key' => 'secretcode'
47
+ })
48
+ define_basic_user_class!
49
+ end
50
+
51
+ define_oauth_user_class!
@@ -0,0 +1,51 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe TwitterAuth::Cryptify do
4
+ before do
5
+ stub_basic!
6
+ end
7
+
8
+ it 'should have encrypt and decrypt methods' do
9
+ TwitterAuth::Cryptify.should respond_to(:encrypt)
10
+ TwitterAuth::Cryptify.should respond_to(:decrypt)
11
+ end
12
+
13
+ describe '.encrypt' do
14
+ it 'should return a hash with :encrypted_data and :salt keys' do
15
+ result = TwitterAuth::Cryptify.encrypt('some string')
16
+ result.should be_a(Hash)
17
+ result.key?(:encrypted_data).should be_true
18
+ result.key?(:salt).should be_true
19
+ end
20
+
21
+ it 'should make a call to EzCrypto::Key.encrypt_with_password' do
22
+ EzCrypto::Key.should_receive(:encrypt_with_password).once.and_return('gobbledygook')
23
+ TwitterAuth::Cryptify.encrypt('some string')
24
+ end
25
+
26
+ it 'should not have the same encrypted as plaintext data' do
27
+ TwitterAuth::Cryptify.encrypt('some string')[:encrypted_data].should_not == 'some string'
28
+ end
29
+ end
30
+
31
+ describe '.decrypt' do
32
+ before do
33
+ @salt = TwitterAuth::Cryptify.generate_salt
34
+ TwitterAuth::Cryptify.stub!(:generate_salt).and_return(@salt)
35
+ @string = 'decrypted string'
36
+ @encrypted = TwitterAuth::Cryptify.encrypt(@string)
37
+ end
38
+
39
+ it 'should return the original string' do
40
+ TwitterAuth::Cryptify.decrypt(@encrypted).should == @string
41
+ end
42
+
43
+ it 'should raise an argument error if encrypted data is provided without a salt' do
44
+ lambda{TwitterAuth::Cryptify.decrypt('asodiaoie2')}.should raise_error(ArgumentError)
45
+ end
46
+
47
+ it 'should raise an argument error if a string or hash are not provided' do
48
+ lambda{TwitterAuth::Cryptify.decrypt(23)}.should raise_error(ArgumentError)
49
+ end
50
+ end
51
+ end