devise-twitter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ .rvmrc
5
+ session.vim
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in devise-twitter.gemspec
4
+ gemspec
@@ -0,0 +1,30 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ devise-twitter (0.0.1)
5
+ devise (>= 1.1.0)
6
+ warden_oauth (~> 0.1.1)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ bcrypt-ruby (2.1.2)
12
+ devise (1.1.2)
13
+ bcrypt-ruby (~> 2.1.2)
14
+ warden (~> 0.10.7)
15
+ oauth (0.4.3)
16
+ rack (1.2.1)
17
+ warden (0.10.7)
18
+ rack (>= 1.0.0)
19
+ warden_oauth (0.1.1)
20
+ oauth
21
+ warden (>= 0.8.1)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ bundler (>= 1.0.0)
28
+ devise (>= 1.1.0)
29
+ devise-twitter!
30
+ warden_oauth (~> 0.1.1)
@@ -0,0 +1,21 @@
1
+ Copyright 2010 Martin Schuerrer. http://www.schuerrer.org
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,145 @@
1
+ devise-twitter
2
+ ==========
3
+
4
+ Devise-twitter adds **Sign in via Twitter** and **Connect your account to
5
+ Twitter** functionality to your [devise][1] app.
6
+
7
+ It requires at least Devise 1.1 and ONLY works with Rails 3.
8
+
9
+ Current status
10
+ --------------
11
+
12
+ Devise-twitter currently supports *Sign in via Twitter* and *Connect your
13
+ account to Twitter*, but no proper API for *Connect your account to Twitter*
14
+ exists so far.
15
+
16
+ This plugin is in use in an upcoming product and continues to be improved.
17
+
18
+ Installation
19
+ ------------
20
+
21
+ Simply add devise-twitter to your Gemfile and bundle it up:
22
+
23
+ gem 'devise-twitter'
24
+
25
+ Run the generator, supplying the name of the model (e.g. User)
26
+
27
+ $ rails generate devise:twitter user
28
+
29
+ Add your OAuth credentials to `config/initializers/devise_twitter.rb`
30
+
31
+ Devise::Twitter.setup do |config|
32
+ config.consumer_key = <YOUR CONSUMER KEY HERE>
33
+ config.consumer_secret = <YOUR CONSUMER SECRET HERE>
34
+ config.scope = :user
35
+ end
36
+
37
+ Modify your user model like so
38
+
39
+ class User < ActiveRecord::Base
40
+ # To use devise-twitter don't forget to include the :twitter_oauth module:
41
+ # e.g. devise :database_authenticatable, ... , :twitter_oauth
42
+
43
+ # IMPORTANT: If you want to support sign in via twitter you MUST remove the
44
+ # :validatable module, otherwise the user will never be saved
45
+ # since it's email and password is blank.
46
+ # :validatable checks only email and password so it's safe to remove
47
+
48
+ # Include default devise modules. Others available are:
49
+ # :token_authenticatable, :confirmable, :lockable and :timeoutable
50
+ devise :database_authenticatable, :registerable,
51
+ :recoverable, :rememberable, :trackable :twitter_oauth
52
+
53
+ # Setup accessible (or protected) attributes for your model
54
+ attr_accessible :email, :password, :password_confirmation, :remember_me
55
+ end
56
+
57
+
58
+ Modify the generated routes (in `config/routes.rb`) to your liking
59
+
60
+ Application.routes.draw do
61
+ devise_for :user do
62
+ match '/user/sign_in/twitter' => Devise::Twitter::Rack::Signin
63
+ match '/user/connect/twitter' => Devise::Twitter::Rack::Connect
64
+ end
65
+ ...
66
+
67
+ Run the generated migration
68
+
69
+ $ rake db:migrate
70
+
71
+
72
+
73
+ Signing in via Twitter
74
+ ----------------------
75
+
76
+ When signing in via Twitter, after authorizing access on www.twitter.com,
77
+ devise-twitter will sign in an existing user or create a new one, if no user
78
+ with these oauth credentials exists.
79
+
80
+
81
+ Connect your account to Twitter
82
+ -------------------------------
83
+
84
+ Devise-twitter supports adding Twitter credentials to an existing user account
85
+ (e.g. one that registered via email/password) but currently the API to expose
86
+ this feature is far from perfect:
87
+
88
+ After navigating to `/user/connect/twitter` and authorizing access on
89
+ www.twitter.com, devise-twitter checks if there is another user with the same
90
+ twitter handle. If not devise-twitter adds twitter handle and oauth credentials
91
+ to the current user and saves.
92
+
93
+ If another user with the same twitter handle is found devise-twitter sets the
94
+ session variable `warden.user.twitter.connected_user.key` to the id of this
95
+ user. Your application can check if this variable is set and display an option
96
+ to merge the two users.
97
+
98
+ if connected_user = session['warden.user.twitter.connected_user.key'].present?
99
+ connected_user = User.find(connected_user)
100
+
101
+ # Ask user if she/he wants to merge her/his accounts
102
+ # (or just go ahead and merge them)
103
+ end
104
+
105
+ If you have any idea how to improve it, please message me.
106
+
107
+ Database changes
108
+ ----------------
109
+
110
+ The generated migration adds three fields to your user model:
111
+
112
+ change_table(:users) do |t|
113
+ t.column :twitter_handle, :string
114
+ t.column :twitter_oauth_token, :string
115
+ t.column :twitter_oauth_secret, :string
116
+ end
117
+
118
+ add_index :users, :twitter_handle, :unique => true
119
+ add_index :users, [:twitter_oauth_token, :twitter_oauth_secret]
120
+
121
+ Currently the names of these fields are hard coded, but making them
122
+ customizable is on the roadmap.
123
+
124
+
125
+
126
+ Acknowledgements
127
+ ----------------
128
+
129
+ Thanks to
130
+
131
+ * [Daniel Neighman](http://twitter.com/hassox) for creating warden, the framework Devise uses
132
+ * [Jose Valim](http://twitter.com/josevalim) for creating Devise
133
+ * [Pelle Braendgaard](http://stakeventures.com/pages/whoami) for implementing oauth support in Ruby
134
+ * [Roman Gonzalez](http://www.romanandreg.com/) for creating warden_oauth, the framework devise-twitter uses
135
+ * all the other giants who's shoulders this project stands on
136
+
137
+
138
+ Meta
139
+ ----
140
+
141
+ * Code: `git clone http://github.com/MSch/devise-twitter`
142
+ * Bugs: <http://github.com/MSch/devise-twitter/issues>
143
+ * Gems: <http://rubygems.org/gems/devise-twitter>
144
+
145
+ [1]:http://github.com/plataformatec/devise
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/devise/twitter/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "devise-twitter"
6
+ s.version = Devise::Twitter::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ['Martin Schuerrer']
9
+ s.email = ['martin@schuerrer.org']
10
+ s.homepage = "http://github.com/MSch/devise-twitter"
11
+ s.summary = "Sign in via Twitter and Connect your account to Twitter functionality for your Devise/Rails app"
12
+ s.description = "Check out the README for comprehensive documentation"
13
+
14
+ s.required_rubygems_version = ">= 1.3.6"
15
+ s.rubyforge_project = "devise-twitter"
16
+
17
+ # FIXME: Seems like bundler can't handle [">= 1.1.0", "< 1.3.0"]
18
+ s.add_dependency "devise", ">= 1.1.0"
19
+ s.add_dependency "warden_oauth", "~> 0.1.1"
20
+ s.add_development_dependency "bundler", ">= 1.0.0"
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
24
+ s.require_path = 'lib'
25
+ end
@@ -0,0 +1,14 @@
1
+ module Devise
2
+ module Twitter
3
+ end
4
+ end
5
+
6
+ require "rack"
7
+ require "warden"
8
+ require "oauth"
9
+ require "warden_oauth"
10
+ require "devise"
11
+ require "devise/twitter"
12
+ require "devise/twitter/rack"
13
+ require "devise/twitter/warden"
14
+ require "devise/twitter/version"
@@ -0,0 +1,39 @@
1
+ module Devise
2
+ module Twitter
3
+ @@setup_done = false
4
+
5
+ mattr_accessor :consumer_key
6
+ @@consumer_key = nil
7
+
8
+ # Private methods to interface with Warden.
9
+ mattr_accessor :consumer_secret
10
+ @@consumer_secret = nil
11
+
12
+ mattr_accessor :scope
13
+ @@scope = nil
14
+
15
+ # Default way to setup Devise. Run rails generate devise_install to create
16
+ # a fresh initializer with all configuration values.
17
+ def self.setup
18
+ raise "Can not invoke setup twice" if @@setup_done
19
+ yield self
20
+ @@setup_done = true
21
+
22
+ Devise.warden do |manager|
23
+ manager.oauth(:twitter) do |twitter|
24
+ twitter.consumer_key = @@consumer_key
25
+ twitter.consumer_secret = @@consumer_secret
26
+ twitter.options = {
27
+ :site => "https://api.twitter.com",
28
+ :request_token_path => "/oauth/request_token",
29
+ :access_token_path => "/oauth/access_token",
30
+ :authorize_path => "/oauth/authenticate",
31
+ :realm => "http://api.twitter.com/"
32
+ }
33
+ end
34
+ manager.default_strategies(:scope => @@scope).unshift :twitter_oauth
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,64 @@
1
+ module Devise
2
+ module Twitter
3
+ module Rack
4
+ Signin = proc do |env|
5
+ warden = env['warden']
6
+ session = env['rack.session']
7
+ request = ::Rack::Request.new(env)
8
+ scope = env["devise.mapping"].singular
9
+
10
+ if request.params.include?('oauth_token')
11
+ # We got a redirect from Twitter back
12
+
13
+ # Perform _only_ the twitter_oauth strategy.
14
+ # Emulate _perform_authentication in _warden/proxy.rb
15
+ strategy = warden.send(:_fetch_strategy, :twitter_oauth, scope)
16
+ strategy.authenticate!
17
+ if strategy.user
18
+ warden.set_user(strategy.user, :event => :authentication, :scope => scope)
19
+ end
20
+
21
+ redirect_to Warden::OAuth::Utils.host_with_port(request)
22
+ else
23
+ # Perform the redirect to Twitter
24
+ strategy = warden.send(:_fetch_strategy, :twitter_oauth, scope)
25
+
26
+ # warden_oauth would always redirect to / so we need to hook into it
27
+ request_token = strategy.consumer.get_request_token(:oauth_callback => request.url)
28
+ strategy.instance_variable_set(:@request_token, request_token)
29
+
30
+ # warden_oauth does exactly this if params.include? warden_oauth_provider
31
+ # which we also hack around
32
+ strategy.send(:store_request_token_on_session)
33
+ redirect_to request_token.authorize_url
34
+ end
35
+ end
36
+
37
+ Connect = proc do |env|
38
+ # Check that user exists in DB, otherwise we'll get 'user with access token not found'
39
+ # But since connecting to twitter only makes sense for existing users that's ok
40
+ # TODO: If our user is unobtrusive redirect_to :back
41
+ scope = env["devise.mapping"].singular
42
+ env["warden.#{scope}.twitter.perform_connect"] = true
43
+
44
+ Signin.call(env)
45
+ end
46
+
47
+ private
48
+
49
+ # Stolen from action_dispatch/routing/mapper.rb
50
+ def self.redirect_to(url)
51
+ status = 302 # Found
52
+ body = %(<html><body>You are being <a href="#{ERB::Util.h(url.to_s)}">redirected</a>.</body></html>)
53
+
54
+ headers = {
55
+ 'Location' => url.to_s,
56
+ 'Content-Type' => 'text/html',
57
+ 'Content-Length' => body.length.to_s
58
+ }
59
+
60
+ [ status, headers, [body] ]
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ module Devise
2
+ module Twitter
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,42 @@
1
+ Warden::OAuth.access_token_user_finder(:twitter) do |access_token|
2
+ perform_connect = (env["warden.#{@scope}.twitter.perform_connect"] == true)
3
+ twitter_handle = access_token.params[:screen_name]
4
+ klass = @env['devise.mapping'].class_name.constantize
5
+
6
+ if perform_connect
7
+ # Add twitter_handle to current user
8
+ already_existing_user = klass.find_by_twitter_handle(twitter_handle)
9
+ if already_existing_user.blank?
10
+ # We don't know anyone with this handle, therefore continue with connecting
11
+ user = @env['warden'].user
12
+ user.twitter_handle = twitter_handle
13
+ user.twitter_oauth_token = access_token.token
14
+ user.twitter_oauth_secret = access_token.secret
15
+ user.save
16
+ return user
17
+ else
18
+ # We already have such a user in our DB
19
+ session["warden.#{@scope}.twitter.connected_user.key"] = already_existing_user.id
20
+ return @env['warden'].user
21
+ end
22
+ else
23
+ previous_user = @env['warden'].user
24
+
25
+ # Try to find user by token
26
+ user = klass.find_by_twitter_oauth_token_and_twitter_oauth_secret(access_token.token, access_token.secret)
27
+
28
+ # Since we are logging in a new user we want to make sure the before_logout hook is called
29
+ @env['warden'].logout if previous_user.present?
30
+
31
+ if user.nil?
32
+ # Create user if we don't know him yet
33
+ user = klass.new
34
+ user.twitter_handle = twitter_handle
35
+ user.twitter_oauth_token = access_token.token
36
+ user.twitter_oauth_secret = access_token.secret
37
+ user.save
38
+ end
39
+
40
+ return user
41
+ end
42
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generates for the model with the given NAME a migration file and devise-twitter routes.
3
+
4
+ Example:
5
+ rails generate devise:twitter User
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1 @@
1
+ What you need to do now
@@ -0,0 +1,6 @@
1
+ Devise::Twitter.setup do |config|
2
+ config.consumer_key = <YOUR CONSUMER KEY>
3
+ config.consumer_secret = <YOUR CONSUMER SECRET>
4
+ config.scope = :<%= singular_name %>
5
+ end
6
+
@@ -0,0 +1,23 @@
1
+ class AddDeviseTwitterFieldsTo<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def self.up
3
+ change_table(:<%= table_name %>) do |t|
4
+ t.column :twitter_handle, :string
5
+ t.column :twitter_oauth_token, :string
6
+ t.column :twitter_oauth_secret, :string
7
+ end
8
+
9
+ add_index :<%= table_name %>, :twitter_handle, :unique => true
10
+ add_index :<%= table_name %>, [:twitter_oauth_token, :twitter_oauth_secret]
11
+ end
12
+
13
+ def self.down
14
+ remove_index :<%= table_name %>, :column => :twitter_handle
15
+ remove_index :<%= table_name %>, :column => [:twitter_oauth_token, :twitter_oauth_secret]
16
+
17
+ change_table(:<%= table_name %>) do |t|
18
+ t.remove :twitter_handle, :string
19
+ t.remove :twitter_oauth_token, :string
20
+ t.remove :twitter_oauth_secret, :string
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,47 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ module Devise
4
+ module Generators
5
+ class TwitterGenerator < ActiveRecord::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+ def add_migration
8
+ migration_template "migration.rb", "db/migrate/add_devise_twitter_fields_to_#{table_name}"
9
+ end
10
+
11
+ def inject_devise_twitter_intomodel
12
+ inject_into_class model_path, class_name, <<-CONTENT
13
+ # To use devise-twitter don't forget to include the :twitter_oauth module:
14
+ # e.g. devise :database_authenticatable, ... , :twitter_oauth
15
+
16
+ # IMPORTANT: If you want to support sign in via twitter you MUST remove the
17
+ # :validatable module, otherwise the user will never be saved
18
+ # since it's email and password is blank.
19
+ # :validatable checks only email and password so it's safe to remove
20
+
21
+ CONTENT
22
+ end
23
+
24
+ def copy_initializer
25
+ template "initializer.rb", "config/initializers/devise_twitter.rb"
26
+ end
27
+
28
+ def add_devise_twitter_routes
29
+ route <<-CONTENT
30
+ devise_for :#{singular_name} do
31
+ match '/#{singular_name}/sign_in/twitter' => Devise::Twitter::Rack::Signin
32
+ match '/#{singular_name}/connect/twitter' => Devise::Twitter::Rack::Connect
33
+ end
34
+ CONTENT
35
+ end
36
+
37
+ def show_readme
38
+ readme "README" if behavior == :invoke
39
+ end
40
+
41
+ private
42
+ def model_path
43
+ @model_path ||= File.join("app", "models", "#{file_path}.rb")
44
+ end
45
+ end
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise-twitter
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Martin Schuerrer
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-09-13 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: devise
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 1
30
+ - 1
31
+ - 0
32
+ version: 1.1.0
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: warden_oauth
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 0
45
+ - 1
46
+ - 1
47
+ version: 0.1.1
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: bundler
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 1
60
+ - 0
61
+ - 0
62
+ version: 1.0.0
63
+ type: :development
64
+ version_requirements: *id003
65
+ description: Check out the README for comprehensive documentation
66
+ email:
67
+ - martin@schuerrer.org
68
+ executables: []
69
+
70
+ extensions: []
71
+
72
+ extra_rdoc_files: []
73
+
74
+ files:
75
+ - .gitignore
76
+ - Gemfile
77
+ - Gemfile.lock
78
+ - MIT-LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - devise-twitter.gemspec
82
+ - lib/devise-twitter.rb
83
+ - lib/devise/twitter.rb
84
+ - lib/devise/twitter/rack.rb
85
+ - lib/devise/twitter/version.rb
86
+ - lib/devise/twitter/warden.rb
87
+ - lib/generators/devise/USAGE
88
+ - lib/generators/devise/templates/README
89
+ - lib/generators/devise/templates/initializer.rb
90
+ - lib/generators/devise/templates/migration.rb
91
+ - lib/generators/devise/twitter_generator.rb
92
+ has_rdoc: true
93
+ homepage: http://github.com/MSch/devise-twitter
94
+ licenses: []
95
+
96
+ post_install_message:
97
+ rdoc_options: []
98
+
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ segments:
115
+ - 1
116
+ - 3
117
+ - 6
118
+ version: 1.3.6
119
+ requirements: []
120
+
121
+ rubyforge_project: devise-twitter
122
+ rubygems_version: 1.3.7
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Sign in via Twitter and Connect your account to Twitter functionality for your Devise/Rails app
126
+ test_files: []
127
+