twitter-login 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +6 -6
- data/lib/twitter/login.rb +36 -29
- data/spec/login_spec.rb +38 -22
- metadata +2 -2
data/README.markdown
CHANGED
@@ -28,17 +28,17 @@ frameworks.
|
|
28
28
|
|
29
29
|
## Sinatra
|
30
30
|
enable :sessions
|
31
|
-
use Twitter::Login, :
|
31
|
+
use Twitter::Login, :consumer_key => 'KEY', :secret => 'SECRET'
|
32
32
|
helpers Twitter::Login::Helpers
|
33
33
|
|
34
34
|
## Rails
|
35
35
|
# environment.rb:
|
36
|
-
config.middleware.use Twitter::Login, :
|
36
|
+
config.middleware.use Twitter::Login, :consumer_key => 'KEY', :secret => 'SECRET'
|
37
37
|
|
38
38
|
# application_controller.rb
|
39
39
|
include Twitter::Login::Helpers
|
40
40
|
|
41
|
-
Fill in the `:
|
41
|
+
Fill in the `:consumer_key`, `:secret` placeholders with real values. You're done.
|
42
42
|
|
43
43
|
|
44
44
|
What it does
|
@@ -58,7 +58,7 @@ Configuration
|
|
58
58
|
|
59
59
|
Available options for `Twitter::Login` middleware are:
|
60
60
|
|
61
|
-
* `:
|
61
|
+
* `:consumer_key` -- OAuth consumer key *(required)*
|
62
62
|
* `:secret` -- OAuth secret *(required)*
|
63
63
|
* `:login_path` -- where user goes to login (default: "/login")
|
64
64
|
* `:return_to` -- where user goes after login (default: "/")
|
@@ -72,8 +72,8 @@ The `Twitter::Login::Helpers` module (for Sinatra, Rails) adds these methods to
|
|
72
72
|
* `twitter_user` (Hashie::Mash) -- Info about authenticated user. Check this object to
|
73
73
|
know whether there is a currently logged-in user. Access user data like `twitter_user.screen_name`
|
74
74
|
* `twitter_logout` -- Erases info about Twitter login from session, effectively logging-out the Twitter user
|
75
|
-
* `
|
76
|
-
With it you can query anything on behalf of authenticated user, e.g. `
|
75
|
+
* `twitter_client` (Twitter::Base) -- An OAuth consumer client from ["twitter" gem][gem].
|
76
|
+
With it you can query anything on behalf of authenticated user, e.g. `twitter_client.friends_timeline`
|
77
77
|
|
78
78
|
[register]: http://twitter.com/apps/new
|
79
79
|
[gem]: http://rdoc.info/projects/jnunemaker/twitter
|
data/lib/twitter/login.rb
CHANGED
@@ -5,20 +5,23 @@ require 'hashie/mash'
|
|
5
5
|
class Twitter::Login
|
6
6
|
attr_reader :options
|
7
7
|
|
8
|
-
|
9
|
-
:
|
10
|
-
|
11
|
-
|
8
|
+
class << self
|
9
|
+
attr_accessor :consumer_key, :secret
|
10
|
+
end
|
11
|
+
|
12
|
+
DEFAULTS = { :login_path => '/login', :return_to => '/' }
|
12
13
|
|
13
14
|
def initialize(app, options)
|
14
15
|
@app = app
|
15
16
|
@options = DEFAULTS.merge options
|
17
|
+
self.class.consumer_key, self.class.secret = @options[:consumer_key], @options[:secret]
|
16
18
|
end
|
17
19
|
|
18
20
|
def call(env)
|
19
21
|
request = Request.new(env)
|
20
22
|
|
21
23
|
if request.get? and request.path == options[:login_path]
|
24
|
+
@oauth = nil
|
22
25
|
# detect if Twitter redirected back here
|
23
26
|
if request[:oauth_verifier]
|
24
27
|
handle_twitter_authorization(request) do
|
@@ -26,7 +29,7 @@ class Twitter::Login
|
|
26
29
|
end
|
27
30
|
elsif request[:denied]
|
28
31
|
# user refused to log in with Twitter, so give up
|
29
|
-
|
32
|
+
handle_denied_access(request)
|
30
33
|
else
|
31
34
|
# user clicked to login; send them to Twitter
|
32
35
|
redirect_to_twitter(request)
|
@@ -37,13 +40,14 @@ class Twitter::Login
|
|
37
40
|
end
|
38
41
|
|
39
42
|
module Helpers
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
+
def twitter_client
|
44
|
+
oauth = twitter_oauth
|
45
|
+
oauth.authorize_from_access(*session[:access_token])
|
46
|
+
Twitter::Base.new oauth
|
43
47
|
end
|
44
48
|
|
45
|
-
def
|
46
|
-
OAuth::
|
49
|
+
def twitter_oauth
|
50
|
+
Twitter::OAuth.new Twitter::Login.consumer_key, Twitter::Login.secret
|
47
51
|
end
|
48
52
|
|
49
53
|
def twitter_user
|
@@ -53,7 +57,7 @@ class Twitter::Login
|
|
53
57
|
end
|
54
58
|
|
55
59
|
def twitter_logout
|
56
|
-
[:
|
60
|
+
[:access_token, :twitter_user].each do |key|
|
57
61
|
session[key] = nil # work around a Rails 2.3.5 bug
|
58
62
|
session.delete key
|
59
63
|
end
|
@@ -83,17 +87,16 @@ class Twitter::Login
|
|
83
87
|
|
84
88
|
def redirect_to_twitter(request)
|
85
89
|
# create a request token and store its parameter in session
|
86
|
-
|
87
|
-
request.session[:request_token] = [
|
90
|
+
oauth.set_callback_url(request.url)
|
91
|
+
request.session[:request_token] = [oauth.request_token.token, oauth.request_token.secret]
|
88
92
|
# redirect to Twitter authorization page
|
89
|
-
redirect
|
93
|
+
redirect oauth.request_token.authorize_url
|
90
94
|
end
|
91
95
|
|
92
96
|
def handle_twitter_authorization(request)
|
93
|
-
|
97
|
+
authorize_from_request(request)
|
94
98
|
|
95
99
|
# get and store authenticated user's info from Twitter
|
96
|
-
twitter = Twitter::Base.new access_token
|
97
100
|
request.session[:twitter_user] = twitter.verify_credentials.to_hash
|
98
101
|
|
99
102
|
# pass the request down to the main app
|
@@ -109,20 +112,21 @@ class Twitter::Login
|
|
109
112
|
end
|
110
113
|
end
|
111
114
|
|
115
|
+
def handle_denied_access(request)
|
116
|
+
request.session[:request_token] = nil # work around a Rails 2.3.5 bug
|
117
|
+
request.session.delete(:request_token)
|
118
|
+
redirect_to_return_path(request)
|
119
|
+
end
|
120
|
+
|
112
121
|
private
|
113
122
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
123
|
+
# replace the request token in session with access token
|
124
|
+
def authorize_from_request(request)
|
125
|
+
rtoken, rsecret = request.session[:request_token]
|
126
|
+
oauth.authorize_from_request(rtoken, rsecret, request[:oauth_verifier])
|
118
127
|
|
119
|
-
# store access token and OAuth consumer parameters in session
|
120
128
|
request.session.delete(:request_token)
|
121
|
-
request.session[:access_token] = [access_token.token, access_token.secret]
|
122
|
-
consumer = access_token.consumer
|
123
|
-
request.session[:oauth_consumer] = [consumer.key, consumer.secret, consumer.options]
|
124
|
-
|
125
|
-
return access_token
|
129
|
+
request.session[:access_token] = [oauth.access_token.token, oauth.access_token.secret]
|
126
130
|
end
|
127
131
|
|
128
132
|
def redirect_to_return_path(request)
|
@@ -133,8 +137,11 @@ class Twitter::Login
|
|
133
137
|
["302", {'Location' => url, 'Content-type' => 'text/plain'}, []]
|
134
138
|
end
|
135
139
|
|
136
|
-
def
|
137
|
-
::OAuth
|
138
|
-
|
140
|
+
def oauth
|
141
|
+
@oauth ||= Twitter::OAuth.new options[:consumer_key], options[:secret], :sign_in => true
|
142
|
+
end
|
143
|
+
|
144
|
+
def twitter
|
145
|
+
Twitter::Base.new oauth
|
139
146
|
end
|
140
147
|
end
|
data/spec/login_spec.rb
CHANGED
@@ -21,7 +21,7 @@ describe Twitter::Login do
|
|
21
21
|
|
22
22
|
builder = Rack::Builder.new
|
23
23
|
builder.use Rack::Session::Cookie
|
24
|
-
builder.use described_class, :
|
24
|
+
builder.use described_class, :consumer_key => 'abc', :secret => '123'
|
25
25
|
builder.run main_app
|
26
26
|
builder.to_app
|
27
27
|
end
|
@@ -31,12 +31,21 @@ describe Twitter::Login do
|
|
31
31
|
@request = Rack::MockRequest.new(@app)
|
32
32
|
end
|
33
33
|
|
34
|
+
it "should expose consumer key/secret globally" do
|
35
|
+
Twitter::Login.consumer_key.should == 'abc'
|
36
|
+
Twitter::Login.secret.should == '123'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should ignore normal requests" do
|
40
|
+
get('/', :lint => true)
|
41
|
+
response.status.should == 200
|
42
|
+
response.body.should == 'Hello world'
|
43
|
+
end
|
44
|
+
|
34
45
|
it "should login with Twitter" do
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
# request.session[:request_token] = token
|
39
|
-
# redirect token.authorize_url
|
46
|
+
request_token = mock('Request Token', :authorize_url => 'http://disney.com/oauth', :token => 'abc', :secret => '123')
|
47
|
+
oauth = mock_oauth('Twitter OAuth', :request_token => request_token)
|
48
|
+
oauth.should_receive(:set_callback_url).with('http://example.org/login')
|
40
49
|
|
41
50
|
get('/login', :lint => true)
|
42
51
|
response.status.should == 302
|
@@ -46,31 +55,40 @@ describe Twitter::Login do
|
|
46
55
|
end
|
47
56
|
|
48
57
|
it "should authorize with Twitter" do
|
49
|
-
consumer =
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
request_token.should_receive(:get_access_token).with(:oauth_verifier => 'abc').and_return(access_token)
|
58
|
+
consumer = mock('OAuth consumer')
|
59
|
+
access_token = mock('Access Token', :token => 'access1', :secret => '42')
|
60
|
+
oauth = mock_oauth('Twitter OAuth', :access_token => access_token, :consumer => consumer)
|
61
|
+
oauth.should_receive(:authorize_from_request).with('abc', '123', 'allrighty')
|
54
62
|
|
55
63
|
twitter = mock('Twitter Base')
|
56
|
-
Twitter::Base.should_receive(:new).with(
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
64
|
+
Twitter::Base.should_receive(:new).with(oauth).and_return(twitter)
|
65
|
+
|
66
|
+
twitter.should_receive(:verify_credentials).and_return {
|
67
|
+
Hashie::Mash.new :screen_name => 'faker',
|
68
|
+
:name => 'Fake Jr.', :profile_image_url => 'http://disney.com/mickey.png',
|
69
|
+
:followers_count => '13', :friends_count => '6', :statuses_count => '52'
|
70
|
+
}
|
61
71
|
|
62
72
|
session_data = {:request_token => ['abc', '123']}
|
63
|
-
get('/login?oauth_verifier=
|
73
|
+
get('/login?oauth_verifier=allrighty', build_session(session_data).update(:lint => true))
|
64
74
|
response.status.should == 302
|
65
75
|
response['Location'].should == 'http://example.org/'
|
66
76
|
session[:request_token].should be_nil
|
67
77
|
session[:access_token].should == ['access1', '42']
|
68
|
-
session[:oauth_consumer].should
|
78
|
+
session[:oauth_consumer].should be_nil
|
69
79
|
|
70
80
|
current_user = session[:twitter_user]
|
71
81
|
current_user['screen_name'].should == 'faker'
|
72
82
|
end
|
73
83
|
|
84
|
+
it "should handle denied access" do
|
85
|
+
session_data = {:request_token => ['abc', '123']}
|
86
|
+
get('/login?denied=OMG', build_session(session_data).update(:lint => true))
|
87
|
+
response.status.should == 302
|
88
|
+
response['Location'].should == 'http://example.org/'
|
89
|
+
session[:request_token].should be_nil
|
90
|
+
end
|
91
|
+
|
74
92
|
protected
|
75
93
|
|
76
94
|
[:get, :post, :put, :delete, :head].each do |method|
|
@@ -104,11 +122,9 @@ describe Twitter::Login do
|
|
104
122
|
[Marshal.dump(obj)].pack('m*')
|
105
123
|
end
|
106
124
|
|
107
|
-
def
|
125
|
+
def mock_oauth(*args)
|
108
126
|
consumer = mock(*args)
|
109
|
-
OAuth
|
110
|
-
# .with(instance_of(String), instance_of(String),
|
111
|
-
# :site => 'http://twitter.com', :authorize_path => '/oauth/authenticate')
|
127
|
+
Twitter::OAuth.should_receive(:new).and_return(consumer)
|
112
128
|
consumer
|
113
129
|
end
|
114
130
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twitter-login
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Mislav Marohni\xC4\x87"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-04 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|