challah-facebook 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +3 -0
- data/README.md +26 -0
- data/lib/challah/facebook/interface.rb +36 -0
- data/lib/challah/facebook/interfaces/base.rb +46 -0
- data/lib/challah/facebook/interfaces/fb_graph.rb +65 -0
- data/lib/challah/facebook/interfaces/koala.rb +11 -0
- data/lib/challah/facebook/provider.rb +59 -0
- data/lib/challah/facebook/technique.rb +29 -0
- data/lib/challah/facebook/version.rb +5 -0
- data/lib/challah/facebook.rb +9 -0
- data/lib/challah-facebook.rb +7 -0
- data/test/helper.rb +121 -0
- metadata +106 -0
data/CHANGELOG.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# challah-facebook
|
2
|
+
|
3
|
+
`challah-facebook` is an extension to the [Challah](http://github.com/jdtornow/challah) gem that allows users to register and authenticate with the Facebook graph API (Facebook Connect.)
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
* Ruby 1.9.2+
|
8
|
+
* Bundler
|
9
|
+
* Rails 3.1+
|
10
|
+
* Challah Gem 0.9+
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
gem install challah
|
15
|
+
gem install challah-facebook
|
16
|
+
|
17
|
+
Or, in your `Gemfile`
|
18
|
+
|
19
|
+
gem 'challah', '>= 0.9'
|
20
|
+
gem 'challah-facebook'
|
21
|
+
|
22
|
+
## License
|
23
|
+
|
24
|
+
`challah-facebook` is released under the [MIT license](http://www.opensource.org/licenses/MIT)
|
25
|
+
|
26
|
+
Contributions and pull-requests are more than welcome.
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'challah/facebook/interfaces/base'
|
2
|
+
|
3
|
+
# Set up the proper interface depending on installed gems
|
4
|
+
if defined?(FbGraph)
|
5
|
+
require 'challah/facebook/interfaces/fb_graph'
|
6
|
+
|
7
|
+
module Challah
|
8
|
+
module Facebook
|
9
|
+
class Interface < Challah::Facebook::Interfaces::FbGraph
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
elsif defined?(Koala)
|
14
|
+
require 'challah/facebook/interfaces/koala'
|
15
|
+
|
16
|
+
module Challah
|
17
|
+
module Facebook
|
18
|
+
class Interface < Challah::Facebook::Interfaces::Koala
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
else
|
23
|
+
module Challah
|
24
|
+
module Facebook
|
25
|
+
class Interface
|
26
|
+
def self.mode
|
27
|
+
"none"
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing
|
31
|
+
raise "No Facebook adapter found. Please install fb_graph or koala gem to use Facebook"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Challah
|
2
|
+
module Facebook
|
3
|
+
module Interfaces
|
4
|
+
class Base
|
5
|
+
attr_reader :app_id, :app_secret
|
6
|
+
|
7
|
+
def self.app_id
|
8
|
+
ENV['FACEBOOK_APP_ID']
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.app_secret
|
12
|
+
ENV['FACEBOOK_SECRET']
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.permissions
|
16
|
+
ENV['FACEBOOK_PERMISSIONS'].to_s.split(',')
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.user_fields
|
20
|
+
%w( first_name last_name email )
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(app_id, app_secret)
|
24
|
+
@app_id = app_id
|
25
|
+
@app_secret = app_secret
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.get_access_token_for_oauth_code(code, callback_uri)
|
29
|
+
raise 'Not implemented: get_access_token_for_oauth_code'
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.get_access_token_from_cookies(cookies_hash)
|
33
|
+
raise 'Not implemented: get_access_token_from_cookies'
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.get_facebook_uid_from_access_token(access_token)
|
37
|
+
raise 'Not implemented: get_facebook_uid_from_access_token'
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.get_authorization_url(callback_uri, permissions = nil)
|
41
|
+
raise 'Not implemented: get_authorization_url'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Challah
|
2
|
+
module Facebook
|
3
|
+
module Interfaces
|
4
|
+
class FbGraph < Base
|
5
|
+
def self.mode
|
6
|
+
"fb_graph"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.get_access_token_for_oauth_code(code, callback_uri)
|
10
|
+
client = new(app_id, app_secret).auth(callback_uri).client
|
11
|
+
client.authorization_code = code
|
12
|
+
client.access_token!(:client_auth_body).to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get_access_token_from_cookies(cookies_hash)
|
16
|
+
fb_auth = new(app_id, app_secret).auth
|
17
|
+
fb_auth.from_cookie(cookies_hash)
|
18
|
+
fb_auth.access_token.to_s
|
19
|
+
rescue
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.get_extended_token(access_token)
|
24
|
+
fb_auth = new(app_id, app_secret).auth
|
25
|
+
fb_auth.exchange_token!(access_token)
|
26
|
+
fb_auth.access_token.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.get_facebook_uid_from_access_token(access_token)
|
30
|
+
fb_user = ::FbGraph::User.me(access_token).fetch
|
31
|
+
|
32
|
+
if fb_user
|
33
|
+
return fb_user.identifier.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
nil
|
37
|
+
rescue
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.get_user_info_from_access_token(access_token)
|
42
|
+
result = {}
|
43
|
+
|
44
|
+
fb_user = ::FbGraph::User.me(access_token).fetch
|
45
|
+
|
46
|
+
self.user_fields.each do |field|
|
47
|
+
result[field] = fb_user.send(field)
|
48
|
+
end
|
49
|
+
|
50
|
+
result
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.get_authorization_url(callback_uri, permissions = nil)
|
54
|
+
scope = self.permissions if scope.nil?
|
55
|
+
client = new(app_id, app_secret).auth(callback_uri).client
|
56
|
+
client.authorization_uri(scope: scope)
|
57
|
+
end
|
58
|
+
|
59
|
+
def auth(callback_uri = nil)
|
60
|
+
::FbGraph::Auth.new(app_id, app_secret, redirect_uri: callback_uri)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Challah
|
2
|
+
module Facebook
|
3
|
+
class Provider
|
4
|
+
def self.save(record)
|
5
|
+
set({
|
6
|
+
user_id: record.id,
|
7
|
+
token: record.facebook_provider.fetch(:token),
|
8
|
+
uid: record.facebook_provider.fetch(:uid)
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.set(options = {})
|
13
|
+
user_id = options.fetch(:user_id)
|
14
|
+
uid = options.fetch(:uid, '')
|
15
|
+
token = options.fetch(:token, '')
|
16
|
+
|
17
|
+
::Authorization.set({
|
18
|
+
provider: :facebook,
|
19
|
+
user_id: user_id,
|
20
|
+
uid: uid,
|
21
|
+
token: token
|
22
|
+
})
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.valid?(user)
|
26
|
+
return false unless user.facebook_provider?
|
27
|
+
|
28
|
+
uid = user.facebook_provider.fetch(:uid).to_s.strip
|
29
|
+
token = user.facebook_provider.fetch(:token)
|
30
|
+
|
31
|
+
# Both a fb_uid and access token are required
|
32
|
+
if uid.present? and token.present?
|
33
|
+
if ::Authorization.where(provider: 'facebook', uid: uid).count > 0
|
34
|
+
user.errors.add :facebook, 'account has already been used'
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
# Get extended token
|
40
|
+
extended_token = Interface.get_extended_token(token)
|
41
|
+
user.facebook_provider[:token] = extended_token
|
42
|
+
|
43
|
+
# Verify UID
|
44
|
+
test_uid = Interface.get_facebook_uid_from_access_token(extended_token)
|
45
|
+
|
46
|
+
# If the uid's match up, this is a valid token
|
47
|
+
return test_uid == uid
|
48
|
+
rescue
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
|
52
|
+
true
|
53
|
+
else
|
54
|
+
false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Challah
|
2
|
+
module Facebook
|
3
|
+
class Technique
|
4
|
+
def initialize(session)
|
5
|
+
@provider = session.provider? ? session.provider : nil
|
6
|
+
@token = session.token? ? session.token : nil
|
7
|
+
@uid = session.uid? ? session.uid : nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def authenticate
|
11
|
+
return nil unless @provider == 'facebook'
|
12
|
+
return nil unless @token
|
13
|
+
|
14
|
+
token = Interface.get_extended_token(@token)
|
15
|
+
auth = ::Authorization.where(provider: 'facebook', token: token, uid: @uid).first
|
16
|
+
|
17
|
+
if auth
|
18
|
+
return auth.user
|
19
|
+
end
|
20
|
+
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def persist?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# Coverage reporting, needs to be loaded first to capture all code coverage stats
|
2
|
+
require 'simplecov'
|
3
|
+
|
4
|
+
# Setup a sample rails app for testing rails modules
|
5
|
+
sample_root = File.expand_path(File.join(File.dirname(__FILE__), '..', 'tmp', 'sampleapp'))
|
6
|
+
FileUtils.rm_rf(sample_root) if File.exists?(sample_root)
|
7
|
+
`rails new #{sample_root} --skip-bundle --skip-sprockets`
|
8
|
+
|
9
|
+
# Setup environment variables for the Rails instance
|
10
|
+
ENV['RAILS_ENV'] = 'test'
|
11
|
+
ENV['BUNDLE_GEMFILE'] ||= File.join(sample_root, 'Gemfile')
|
12
|
+
|
13
|
+
# Load the newly created rails instance environment
|
14
|
+
require "#{sample_root}/config/environment"
|
15
|
+
|
16
|
+
# Some other dependencies for testing w/ shoulda and factory girl
|
17
|
+
require 'shoulda'
|
18
|
+
require 'mocha/setup'
|
19
|
+
require 'factory_girl'
|
20
|
+
require 'factories'
|
21
|
+
require 'rails/test_help'
|
22
|
+
|
23
|
+
# Load the challah libraries
|
24
|
+
require 'challah'
|
25
|
+
require 'challah/facebook'
|
26
|
+
require 'challah/test'
|
27
|
+
|
28
|
+
# Setup the challah app, including running migrations within the rails app
|
29
|
+
# TODO - this causes some annoying output in 1.9.3, still works, but would like to suppress
|
30
|
+
`rake --rakefile #{File.join(sample_root, 'Rakefile')} challah:setup:migrations`
|
31
|
+
|
32
|
+
# Run migrations for the sample app, hiding output
|
33
|
+
ActiveRecord::Migration.verbose = false
|
34
|
+
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
|
35
|
+
|
36
|
+
# Use ActiveSupport::TestCase for any tests using factories and database saving,
|
37
|
+
# so we can have a transactional rollback after each test.
|
38
|
+
class ActiveSupport::TestCase
|
39
|
+
include FactoryGirl::Syntax::Methods
|
40
|
+
|
41
|
+
self.use_transactional_fixtures = true
|
42
|
+
end
|
43
|
+
|
44
|
+
class MockController
|
45
|
+
include Challah::Controller
|
46
|
+
include Challah::Rolls::Controller
|
47
|
+
|
48
|
+
attr_accessor :request, :session, :params
|
49
|
+
|
50
|
+
def initialize()
|
51
|
+
@request = MockRequest.new
|
52
|
+
@session ||= {}
|
53
|
+
@params ||= {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def redirect_to(*args)
|
57
|
+
# do nothing
|
58
|
+
end
|
59
|
+
|
60
|
+
def login_path
|
61
|
+
"/login"
|
62
|
+
end
|
63
|
+
|
64
|
+
def logout_path
|
65
|
+
"/logout"
|
66
|
+
end
|
67
|
+
|
68
|
+
def signin_path
|
69
|
+
"/sign-in"
|
70
|
+
end
|
71
|
+
|
72
|
+
def signout_path
|
73
|
+
"/sign-out"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class MockRequest
|
78
|
+
attr_accessor :cookie_jar, :session_options, :url
|
79
|
+
|
80
|
+
class MockCookieJar < Hash
|
81
|
+
def delete(key, options = {})
|
82
|
+
super(key)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def initialize
|
87
|
+
@cookie_jar = MockCookieJar.new
|
88
|
+
@session_options = { :domain => 'test.dev' }
|
89
|
+
@url = "http://example.com/"
|
90
|
+
end
|
91
|
+
|
92
|
+
def cookies
|
93
|
+
@cookie_jar
|
94
|
+
end
|
95
|
+
|
96
|
+
def cookies=(value)
|
97
|
+
@cookie_jar = value
|
98
|
+
end
|
99
|
+
|
100
|
+
def remote_ip
|
101
|
+
"8.8.8.8"
|
102
|
+
end
|
103
|
+
|
104
|
+
def user_agent
|
105
|
+
"Some Cool Browser"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Monkey patch fix for shoulda and Rails 3.1+.
|
110
|
+
module Shoulda
|
111
|
+
module ActiveRecord
|
112
|
+
module Matchers
|
113
|
+
class AssociationMatcher
|
114
|
+
protected
|
115
|
+
def foreign_key
|
116
|
+
reflection.foreign_key
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: challah-facebook
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- John Tornow
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: challah
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.9.0.pre
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.9.0.pre
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rails
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '3.1'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3.1'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.9.2
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.9.2
|
62
|
+
description: A Challah plugin to allow authentication and registration with Facebook
|
63
|
+
API.
|
64
|
+
email:
|
65
|
+
- john@johntornow.com
|
66
|
+
executables: []
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- test/helper.rb
|
71
|
+
- lib/challah/facebook/interface.rb
|
72
|
+
- lib/challah/facebook/interfaces/base.rb
|
73
|
+
- lib/challah/facebook/interfaces/fb_graph.rb
|
74
|
+
- lib/challah/facebook/interfaces/koala.rb
|
75
|
+
- lib/challah/facebook/provider.rb
|
76
|
+
- lib/challah/facebook/technique.rb
|
77
|
+
- lib/challah/facebook/version.rb
|
78
|
+
- lib/challah/facebook.rb
|
79
|
+
- lib/challah-facebook.rb
|
80
|
+
- README.md
|
81
|
+
- CHANGELOG.md
|
82
|
+
homepage: http://github.com/jdtornow/challah-facebook
|
83
|
+
licenses: []
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.9.2
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.8.23
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: Facebook authentication interface for Challah.
|
106
|
+
test_files: []
|