twitter-login 0.1.0 → 0.2.0
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 +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
|