social_auth 0.0.9
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +39 -0
- data/app/models/social_auth/facebook_service.rb +60 -0
- data/app/models/social_auth/google_plus_service.rb +106 -0
- data/app/models/social_auth/service.rb +152 -0
- data/app/models/social_auth/twitter_service.rb +67 -0
- data/config/routes.rb +2 -0
- data/lib/generators/social_auth/install/install_generator.rb +37 -0
- data/lib/generators/social_auth/install/templates/create_social_auth_services.rb +12 -0
- data/lib/generators/social_auth/install/templates/initializer.rb +15 -0
- data/lib/social_auth.rb +73 -0
- data/lib/social_auth/acts_as_social_user.rb +23 -0
- data/lib/social_auth/engine.rb +12 -0
- data/lib/social_auth/railtie.rb +7 -0
- data/lib/social_auth/version.rb +3 -0
- data/lib/tasks/social_auth_tasks.rake +4 -0
- data/spec/dummy/rails-4.2.0/Gemfile +42 -0
- data/spec/dummy/rails-4.2.0/README.rdoc +28 -0
- data/spec/dummy/rails-4.2.0/Rakefile +6 -0
- data/spec/dummy/rails-4.2.0/app/assets/javascripts/application.js +16 -0
- data/spec/dummy/rails-4.2.0/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/rails-4.2.0/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/rails-4.2.0/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/rails-4.2.0/app/models/user.rb +2 -0
- data/spec/dummy/rails-4.2.0/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/rails-4.2.0/bin/bundle +3 -0
- data/spec/dummy/rails-4.2.0/bin/rails +4 -0
- data/spec/dummy/rails-4.2.0/bin/rake +4 -0
- data/spec/dummy/rails-4.2.0/bin/setup +29 -0
- data/spec/dummy/rails-4.2.0/config.ru +4 -0
- data/spec/dummy/rails-4.2.0/config/application.rb +26 -0
- data/spec/dummy/rails-4.2.0/config/boot.rb +3 -0
- data/spec/dummy/rails-4.2.0/config/database.yml +15 -0
- data/spec/dummy/rails-4.2.0/config/environment.rb +5 -0
- data/spec/dummy/rails-4.2.0/config/environments/development.rb +41 -0
- data/spec/dummy/rails-4.2.0/config/environments/production.rb +79 -0
- data/spec/dummy/rails-4.2.0/config/environments/test.rb +42 -0
- data/spec/dummy/rails-4.2.0/config/initializers/assets.rb +11 -0
- data/spec/dummy/rails-4.2.0/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/rails-4.2.0/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/rails-4.2.0/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/rails-4.2.0/config/initializers/inflections.rb +16 -0
- data/spec/dummy/rails-4.2.0/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/rails-4.2.0/config/initializers/session_store.rb +3 -0
- data/spec/dummy/rails-4.2.0/config/initializers/social_auth.rb +15 -0
- data/spec/dummy/rails-4.2.0/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/rails-4.2.0/config/locales/en.yml +23 -0
- data/spec/dummy/rails-4.2.0/config/routes.rb +56 -0
- data/spec/dummy/rails-4.2.0/config/secrets.yml +22 -0
- data/spec/dummy/rails-4.2.0/db/migrate/20150504044515878_create_social_auth_services.rb +12 -0
- data/spec/dummy/rails-4.2.0/db/migrate/20150504044519_create_users.rb +9 -0
- data/spec/dummy/rails-4.2.0/db/schema.rb +35 -0
- data/spec/dummy/rails-4.2.0/db/seeds.rb +7 -0
- data/spec/dummy/rails-4.2.0/log/test.log +2570 -0
- data/spec/dummy/rails-4.2.0/public/404.html +67 -0
- data/spec/dummy/rails-4.2.0/public/422.html +67 -0
- data/spec/dummy/rails-4.2.0/public/500.html +66 -0
- data/spec/dummy/rails-4.2.0/public/favicon.ico +0 -0
- data/spec/dummy/rails-4.2.0/public/robots.txt +5 -0
- data/spec/dummy/rails-4.2.0/test/fixtures/users.yml +7 -0
- data/spec/dummy/rails-4.2.0/test/models/user_test.rb +7 -0
- data/spec/dummy/rails-4.2.0/test/test_helper.rb +10 -0
- data/spec/fixtures/vcr_cassettes/facebook_service/invalid_friends_request.yml +54 -0
- data/spec/fixtures/vcr_cassettes/facebook_service/invalid_request.yml +50 -0
- data/spec/fixtures/vcr_cassettes/facebook_service/invalid_token.yml +50 -0
- data/spec/fixtures/vcr_cassettes/facebook_service/valid_friends_request.yml +110 -0
- data/spec/fixtures/vcr_cassettes/facebook_service/valid_request.yml +55 -0
- data/spec/fixtures/vcr_cassettes/google_plus_service/invalid_authorization.yml +51 -0
- data/spec/fixtures/vcr_cassettes/google_plus_service/invalid_friends_request.yml +53 -0
- data/spec/fixtures/vcr_cassettes/google_plus_service/invalid_token.yml +51 -0
- data/spec/fixtures/vcr_cassettes/google_plus_service/valid_authorization.yml +56 -0
- data/spec/fixtures/vcr_cassettes/google_plus_service/valid_friends_request.yml +132 -0
- data/spec/fixtures/vcr_cassettes/google_plus_service/valid_request.yml +110 -0
- data/spec/fixtures/vcr_cassettes/twitter_service/invalid_friends_request.yml +47 -0
- data/spec/fixtures/vcr_cassettes/twitter_service/valid_friends_request.yml +159 -0
- data/spec/fixtures/vcr_cassettes/twitter_service/valid_request.yml +337 -0
- data/spec/models/facebook_service_spec.rb +127 -0
- data/spec/models/google_plus_service_spec.rb +133 -0
- data/spec/models/service_spec.rb +236 -0
- data/spec/models/twitter_service_spec.rb +100 -0
- data/spec/spec_helper.rb +74 -0
- data/spec/support/database.yml +15 -0
- data/spec/support/rails_template.rb +15 -0
- metadata +376 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 7b73fa75b8a6c8200dfa7dd06516c356ed7bc6fa
|
|
4
|
+
data.tar.gz: 3df34c0d057b106e60658529905ad5b5d6a3258f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1806f1a18ece05d1522f280a6746b675384708be1933bc87ac940c20f2eefb129af1ae11bb4c8f98272cfb5afbd02cb3fe8bbe4ea20aa4b39fe4e1fc024cd765
|
|
7
|
+
data.tar.gz: 6348918e0a59e0aced64adbb948fc72ca3d86f8658e38a5fa28aa932aee3a1eedd3a1dda83b621c34958e9ef67bb77c2ee000ef21eff00ebc57b4c4572d756b9
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2015 William Porter
|
|
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.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require "bundler"
|
|
2
|
+
require 'rake'
|
|
3
|
+
Bundler.setup
|
|
4
|
+
Bundler::GemHelper.install_tasks
|
|
5
|
+
|
|
6
|
+
def cmd(command)
|
|
7
|
+
puts command
|
|
8
|
+
raise unless system command
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Import all our rake tasks
|
|
12
|
+
FileList['tasks/**/*.rake'].each { |task| import task }
|
|
13
|
+
|
|
14
|
+
# begin
|
|
15
|
+
# require 'bundler/setup'
|
|
16
|
+
# rescue LoadError
|
|
17
|
+
# puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
18
|
+
# end
|
|
19
|
+
|
|
20
|
+
# require 'rdoc/task'
|
|
21
|
+
|
|
22
|
+
# RDoc::Task.new(:rdoc) do |rdoc|
|
|
23
|
+
# rdoc.rdoc_dir = 'rdoc'
|
|
24
|
+
# rdoc.title = 'SocialAuth'
|
|
25
|
+
# rdoc.options << '--line-numbers'
|
|
26
|
+
# rdoc.rdoc_files.include('README.rdoc')
|
|
27
|
+
# rdoc.rdoc_files.include('lib/**/*.rb')
|
|
28
|
+
# end
|
|
29
|
+
|
|
30
|
+
# APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
|
31
|
+
# load 'rails/tasks/engine.rake'
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# load 'rails/tasks/statistics.rake'
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# Bundler::GemHelper.install_tasks
|
|
39
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'fb_graph2'
|
|
2
|
+
|
|
3
|
+
module SocialAuth
|
|
4
|
+
class FacebookService < Service
|
|
5
|
+
def name
|
|
6
|
+
"Facebook"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.init_with(auth_token={})
|
|
10
|
+
request = create_connection(auth_token)
|
|
11
|
+
|
|
12
|
+
return create_with_request(
|
|
13
|
+
request.id,
|
|
14
|
+
User.create_with_facebook_request(request),
|
|
15
|
+
"Authenticated",
|
|
16
|
+
{access_token: request.access_token}
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.connect_with(user, auth_token={}, method="Connected")
|
|
21
|
+
request = create_connection(auth_token)
|
|
22
|
+
|
|
23
|
+
return create_with_request(
|
|
24
|
+
request.id,
|
|
25
|
+
user,
|
|
26
|
+
method,
|
|
27
|
+
{access_token: request.access_token}
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.create_connection(auth_token={})
|
|
32
|
+
fb_user = FbGraph2::User.me(auth_token[:access_token])
|
|
33
|
+
fb_user.fetch
|
|
34
|
+
|
|
35
|
+
rescue FbGraph2::Exception::InvalidToken => e
|
|
36
|
+
raise InvalidToken.new(e.message)
|
|
37
|
+
rescue FbGraph2::Exception::BadRequest => e
|
|
38
|
+
raise BadRequest.new(e.message)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def friend_ids
|
|
42
|
+
if redis_instance.exists(redis_key(:friends))
|
|
43
|
+
friend_ids = redis_instance.smembers(redis_key(:friends))
|
|
44
|
+
else
|
|
45
|
+
friend_ids = self.class.create_connection(access_token).friends.map(&:id)
|
|
46
|
+
unless friend_ids.empty?
|
|
47
|
+
redis_instance.del(redis_key(:friends))
|
|
48
|
+
redis_instance.sadd(redis_key(:friends), friend_ids)
|
|
49
|
+
redis_instance.expire(redis_key(:friends), REDIS_CACHE)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
friend_ids
|
|
53
|
+
|
|
54
|
+
rescue InvalidToken => e
|
|
55
|
+
disconnect(e)
|
|
56
|
+
return []
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require 'google_plus'
|
|
2
|
+
require 'typhoeus'
|
|
3
|
+
|
|
4
|
+
module SocialAuth
|
|
5
|
+
class GooglePlusService < Service
|
|
6
|
+
|
|
7
|
+
def name
|
|
8
|
+
"Google Plus"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.init_with(auth_token={})
|
|
12
|
+
access_token = fetch_access_token(auth_token)
|
|
13
|
+
request = create_connection(access_token).get('me')
|
|
14
|
+
|
|
15
|
+
return create_with_request(
|
|
16
|
+
request.id,
|
|
17
|
+
User.create_with_google_plus_request(request),
|
|
18
|
+
"Authenticated",
|
|
19
|
+
{refresh_token: access_token[:refresh_token]}
|
|
20
|
+
)
|
|
21
|
+
rescue GooglePlus::RequestError => e
|
|
22
|
+
raise InvalidToken.new(e.message)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.connect_with(user, auth_token={}, method="Connected")
|
|
26
|
+
access_token = fetch_access_token(auth_token)
|
|
27
|
+
request = create_connection(access_token).get('me')
|
|
28
|
+
|
|
29
|
+
return create_with_request(
|
|
30
|
+
request.id,
|
|
31
|
+
user,
|
|
32
|
+
method,
|
|
33
|
+
{refresh_token: access_token[:refresh_token]}
|
|
34
|
+
)
|
|
35
|
+
rescue GooglePlus::RequestError => e
|
|
36
|
+
raise InvalidToken.new(e.message)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.fetch_access_token(auth_token={})
|
|
40
|
+
params = {
|
|
41
|
+
client_id: SocialAuth.google_client_id,
|
|
42
|
+
client_secret: SocialAuth.google_client_secret,
|
|
43
|
+
redirect_uri: SocialAuth.google_redirect_uri
|
|
44
|
+
}
|
|
45
|
+
if auth_token[:auth_token].present?
|
|
46
|
+
params[:code] = auth_token[:auth_token]
|
|
47
|
+
params[:grant_type] = "authorization_code"
|
|
48
|
+
request = Typhoeus::Request.new(
|
|
49
|
+
"https://www.googleapis.com/oauth2/v3/token",
|
|
50
|
+
method: :post,
|
|
51
|
+
params: params
|
|
52
|
+
)
|
|
53
|
+
else
|
|
54
|
+
params[:refresh_token] = auth_token[:refresh_token]
|
|
55
|
+
params[:grant_type] = "refresh_token"
|
|
56
|
+
request = Typhoeus::Request.new(
|
|
57
|
+
"https://www.googleapis.com/oauth2/v3/token",
|
|
58
|
+
method: :post,
|
|
59
|
+
params: params
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
request.on_complete do |response|
|
|
64
|
+
body = JSON.parse(response.body).with_indifferent_access
|
|
65
|
+
if response.success?
|
|
66
|
+
return body
|
|
67
|
+
else
|
|
68
|
+
raise InvalidToken.new(body[:error_description])
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
request.run
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.create_connection(auth_token={})
|
|
76
|
+
GooglePlus.api_key = SocialAuth.google_api_key
|
|
77
|
+
GooglePlus.access_token = auth_token[:access_token]
|
|
78
|
+
GooglePlus::Person
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def google_items
|
|
82
|
+
self.class.create_connection(self.class.fetch_access_token(access_token)).list.items
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def friend_ids
|
|
86
|
+
if redis_instance.exists(redis_key(:friends))
|
|
87
|
+
friend_ids = redis_instance.smembers(redis_key(:friends))
|
|
88
|
+
else
|
|
89
|
+
items = google_items
|
|
90
|
+
friend_ids = items.map(&:id) if items.present?
|
|
91
|
+
if friend_ids.present?
|
|
92
|
+
redis_instance.del(redis_key(:friends))
|
|
93
|
+
redis_instance.sadd(redis_key(:friends), friend_ids)
|
|
94
|
+
redis_instance.expire(redis_key(:friends), REDIS_CACHE)
|
|
95
|
+
else
|
|
96
|
+
return []
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
friend_ids
|
|
100
|
+
|
|
101
|
+
rescue InvalidToken => e
|
|
102
|
+
disconnect
|
|
103
|
+
return []
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
module SocialAuth
|
|
2
|
+
class Service < ActiveRecord::Base
|
|
3
|
+
#validations
|
|
4
|
+
validates_presence_of :user, :access_token, :remote_id, :method
|
|
5
|
+
validates_uniqueness_of :remote_id, scope: [:type], :if => lambda { |service| service.method == 'Authenticated' }
|
|
6
|
+
validates_uniqueness_of :remote_id, scope: [:type, :user_id], :if => lambda { |service| service.method == 'Connected' }
|
|
7
|
+
|
|
8
|
+
before_validation :validate_methods
|
|
9
|
+
|
|
10
|
+
#relations
|
|
11
|
+
belongs_to :user
|
|
12
|
+
|
|
13
|
+
#settings
|
|
14
|
+
self.table_name = "social_auth_services"
|
|
15
|
+
|
|
16
|
+
#callbacks
|
|
17
|
+
after_create :append_to_associated_services
|
|
18
|
+
|
|
19
|
+
ACCEPTED_METHODS = %w(Authenticated Connected)
|
|
20
|
+
REDIS_CACHE = 2_592_000 # cache expiry in seconds
|
|
21
|
+
|
|
22
|
+
def name
|
|
23
|
+
raise "need to implement"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def access_token
|
|
27
|
+
if super.blank?
|
|
28
|
+
{}
|
|
29
|
+
else
|
|
30
|
+
super.with_indifferent_access
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.init_with(auth_token)
|
|
35
|
+
raise "need to override"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.connect_with(user, auth_token)
|
|
39
|
+
raise "need to override"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.create_with_request(remote_id, user, method="Connected", access_token={})
|
|
43
|
+
remote_id = remote_id.to_s
|
|
44
|
+
|
|
45
|
+
unless (service = find_by_remote_id_and_method(remote_id, method)) && method == "Authenticated"
|
|
46
|
+
#attempts to look if some other user connected this same facebook account if its an authentication request
|
|
47
|
+
if count = where(remote_id: remote_id, method: "Connected").count == 1 and method == "Authenticated"
|
|
48
|
+
service = find_by_remote_id_and_method(remote_id, "Connected")
|
|
49
|
+
else
|
|
50
|
+
service = new
|
|
51
|
+
service.remote_id = remote_id
|
|
52
|
+
|
|
53
|
+
#gives the owner one last chance to perform some app level logic on the user before being created
|
|
54
|
+
user = user.validate_existing_user(remote_id, service.type) if user.respond_to?(:validate_existing_user)
|
|
55
|
+
service.user = user
|
|
56
|
+
service.method = method
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
service.access_token = access_token
|
|
61
|
+
service.save
|
|
62
|
+
|
|
63
|
+
return service
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def services
|
|
67
|
+
self.class.where('remote_id IN (?)', friend_ids)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.append_to_associated_services(id)
|
|
71
|
+
service = find(id)
|
|
72
|
+
service.services.each do |s|
|
|
73
|
+
s.append_to_friends_list(service)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def append_to_friends_list(service)
|
|
78
|
+
if redis_instance.exists(self.redis_key(:friends))
|
|
79
|
+
redis_instance.sadd(self.redis_key(:friends), service.remote_id)
|
|
80
|
+
end
|
|
81
|
+
user.friend_joined_the_app_callback(service.user) if user.respond_to?(:friend_joined_the_app_callback)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def friend_ids
|
|
85
|
+
if redis_instance.exists(redis_key(:friends))
|
|
86
|
+
friend_ids = redis_instance.smembers(redis_key(:friends))
|
|
87
|
+
else
|
|
88
|
+
[]
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.disconnect_user(user)
|
|
93
|
+
service = find_by_user_id(user.id)
|
|
94
|
+
if service
|
|
95
|
+
raise Error.new("Cannot disconnect a service you used to authenticate with") if service.authenticated?
|
|
96
|
+
|
|
97
|
+
service.disconnect(nil, false)
|
|
98
|
+
else
|
|
99
|
+
raise ServiceDoesNotExist.new("Couldn't find service for this user")
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def disconnect(e=nil, callback=true)
|
|
104
|
+
if connected?
|
|
105
|
+
#destroys service
|
|
106
|
+
self.destroy
|
|
107
|
+
#notifies the user that their service is about to be disconnected
|
|
108
|
+
user.service_disconnected_callback(self) if user.respond_to?(:service_disconnected_callback) and callback
|
|
109
|
+
else
|
|
110
|
+
#re_raises the exception
|
|
111
|
+
raise InvalidToken.new(e ? e.message : "Token has become invalid") #move to localization file
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# helper method to generate redis keys
|
|
116
|
+
def redis_key(str)
|
|
117
|
+
"#{type}:#{id}:#{str}"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def redis_instance
|
|
121
|
+
$redis #need to change out for an configurable var
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def authenticated?
|
|
125
|
+
return true if method == 'Authenticated'
|
|
126
|
+
false
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def connected?
|
|
130
|
+
return true if method == 'Connected'
|
|
131
|
+
false
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
private
|
|
135
|
+
|
|
136
|
+
def validate_methods
|
|
137
|
+
errors.add(:method, 'not an accepted option') unless ACCEPTED_METHODS.include?(method)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def append_to_associated_services
|
|
141
|
+
self.class.delay.append_to_associated_services(self.id)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
#exceptions
|
|
147
|
+
class InvalidToken < StandardError ; end
|
|
148
|
+
class BadRequest < StandardError ; end
|
|
149
|
+
class ServiceDoesNotExist < StandardError ; end
|
|
150
|
+
class Error < StandardError ; end
|
|
151
|
+
|
|
152
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'twitter'
|
|
2
|
+
|
|
3
|
+
module SocialAuth
|
|
4
|
+
class TwitterService < Service
|
|
5
|
+
|
|
6
|
+
def name
|
|
7
|
+
"Twitter"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.init_with(auth_token={})
|
|
11
|
+
request = create_connection(auth_token)
|
|
12
|
+
|
|
13
|
+
return create_with_request(
|
|
14
|
+
request.user.id,
|
|
15
|
+
User.create_with_twitter_request(request.user),
|
|
16
|
+
"Authenticated",
|
|
17
|
+
{access_token: request.access_token, access_token_secret: request.access_token_secret}
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
rescue Twitter::Error::Unauthorized => e
|
|
21
|
+
raise InvalidToken.new(e.message)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.connect_with(user, auth_token={}, method="Connected")
|
|
25
|
+
request = create_connection(auth_token)
|
|
26
|
+
|
|
27
|
+
return create_with_request(
|
|
28
|
+
request.user.id,
|
|
29
|
+
user,
|
|
30
|
+
method,
|
|
31
|
+
{access_token: request.access_token, access_token_secret: request.access_token_secret}
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
rescue Twitter::Error::Unauthorized => e
|
|
35
|
+
raise InvalidToken.new(e.message)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.create_connection(auth_token={})
|
|
39
|
+
Twitter::REST::Client.new do |config|
|
|
40
|
+
config.consumer_key = SocialAuth.twitter_consumer_key
|
|
41
|
+
config.consumer_secret = SocialAuth.twitter_consumer_secret
|
|
42
|
+
config.access_token = auth_token[:access_token]
|
|
43
|
+
config.access_token_secret = auth_token[:access_token_secret]
|
|
44
|
+
end
|
|
45
|
+
#the reason why we don't catch any exceptions here is because it only initializes the connection no
|
|
46
|
+
#requests are actually made here
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def friend_ids
|
|
50
|
+
if redis_instance.exists(redis_key(:friends))
|
|
51
|
+
friend_ids = redis_instance.smembers(redis_key(:friends))
|
|
52
|
+
else
|
|
53
|
+
friend_ids = self.class.create_connection(access_token).friend_ids.to_hash[:ids].map(&:to_s)
|
|
54
|
+
unless friend_ids.empty?
|
|
55
|
+
redis_instance.del(redis_key(:friends))
|
|
56
|
+
redis_instance.sadd(redis_key(:friends), friend_ids.to_s)
|
|
57
|
+
redis_instance.expire(redis_key(:friends), REDIS_CACHE)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
friend_ids
|
|
61
|
+
rescue Twitter::Error::Unauthorized => e
|
|
62
|
+
disconnect
|
|
63
|
+
return []
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
end
|