challah-facebook 0.1.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/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: []
|