facebook_client 0.0.5.0 → 0.0.5.2

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.
@@ -1,12 +1,15 @@
1
+ require 'openssl'
1
2
  require File.dirname(__FILE__)+'/ext'
2
3
 
3
4
  require File.dirname(__FILE__)+'/graph'
4
5
  require File.dirname(__FILE__)+'/auth'
5
6
  require File.dirname(__FILE__)+'/rest_api'
6
7
 
7
- require File.dirname(__FILE__)+'/cookie_session'
8
- require File.dirname(__FILE__)+'/iframe_session'
9
- require File.dirname(__FILE__)+'/legacy_session'
8
+ require File.dirname(__FILE__)+'/session/base'
9
+ require File.dirname(__FILE__)+'/session/cookie'
10
+ require File.dirname(__FILE__)+'/session/fb_sig_param'
11
+ require File.dirname(__FILE__)+'/session/signed_request_param'
12
+ require File.dirname(__FILE__)+'/session/session_param'
10
13
 
11
14
  module FacebookClient
12
15
 
@@ -30,8 +33,8 @@ module FacebookClient
30
33
  @auth ||= Auth.new(self)
31
34
  end
32
35
 
33
- def graph(token, expires=nil)
34
- Graph.new(self,token,expires)
36
+ def graph(token, expires = nil)
37
+ Graph.new(self, token, expires)
35
38
  end
36
39
 
37
40
  def rest_api
data/lib/graph.rb CHANGED
@@ -8,16 +8,14 @@ module FacebookClient
8
8
 
9
9
  attr_reader :access_token
10
10
 
11
- def initialize(fb, access_token, expires=nil)
12
- @fb=fb
13
- @access_token=access_token
14
- if expires.nil?
15
- expires=0
16
- end
17
- expires=expires.to_i
11
+ def initialize(fb, access_token, expires = nil)
12
+ @fb = fb
13
+ @access_token = access_token
14
+ expires = 0 if expires.nil?
15
+ expires = expires.to_i
18
16
  end
19
-
20
- def get(path, params={})
17
+
18
+ def get(path, params = {})
21
19
  params = params.stringify_keys
22
20
  params['access_token'] = @access_token
23
21
  response = connection.run_request(:get, path, nil, {}) do |request|
@@ -0,0 +1,17 @@
1
+ module FacebookClient
2
+
3
+ module Session
4
+
5
+ class Base
6
+
7
+ attr_reader :fb
8
+
9
+ def graph
10
+ @graph ||= Graph.new(fb, access_token, 0)
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,54 @@
1
+ module FacebookClient
2
+
3
+ module Session
4
+
5
+ require 'rack'
6
+ require 'digest'
7
+
8
+ class Cookie < Base
9
+
10
+ def self.create_and_secure(fb, cookies)
11
+ cookie_session = new(fb, cookies)
12
+ cookie_session.secure? ? cookie_session : nil
13
+ end
14
+
15
+ def initialize(fb, cookies)
16
+ @fb=fb
17
+ @data=parse_fbs!(cookies["fbs_#{fb.app_id}"])
18
+ end
19
+
20
+ def parse_fbs!(fbs)
21
+ @data = fbs &&
22
+ check_sig_and_return_data(Rack::Utils.parse_query(fbs[1..-2]))
23
+ end
24
+
25
+ def secure?
26
+ @data.is_a?(Hash) and @data.has_key?('uid')
27
+ end
28
+
29
+ def access_token
30
+ @data['access_token']
31
+ end
32
+
33
+ def uid
34
+ @data['uid']
35
+ end
36
+
37
+ private
38
+
39
+ def check_sig_and_return_data(cookies)
40
+ cookies if calculate_sig(cookies) == cookies['sig']
41
+ end
42
+
43
+ def calculate_sig(cookies)
44
+ args = cookies.reject{ |(k, v)| k == 'sig' }.sort.
45
+ map{ |a| a.join('=') }.join
46
+
47
+ Digest::MD5.hexdigest(args + @fb.secret)
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,64 @@
1
+ module FacebookClient
2
+
3
+ module Session
4
+
5
+ require 'digest'
6
+
7
+ class FbSigParam < Base
8
+
9
+ def self.create_and_secure(fb, params)
10
+ legacy_session = new(fb, params)
11
+
12
+ legacy_session.secure? ? legacy_session : nil
13
+ end
14
+
15
+ def initialize(fb, params)
16
+ @fb=fb
17
+ @params=verfiy_params_and_return(params)
18
+ end
19
+
20
+ def secure?
21
+ @params.is_a?(Hash) and @params.has_key?('user')
22
+ end
23
+
24
+ def uid
25
+ @params['user']
26
+ end
27
+
28
+ def access_token
29
+ @params["session_key"]
30
+ end
31
+
32
+ def verfiy_params_and_return(params)
33
+ if params['fb_sig'].nil? or !params['fb_sig'].is_a?(String)
34
+ log 'missing fb_sig'
35
+ return nil
36
+ end
37
+
38
+ facebook_sig_params = params.inject({}) do |collection, pair|
39
+ collection[pair.first.sub(/^fb_sig_/, '')] = pair.last if pair.first[0,7] == 'fb_sig_'
40
+ collection
41
+ end
42
+
43
+ if params['fb_sig']==calculate_sig(facebook_sig_params)
44
+ log "secured for #{facebook_sig_params['user']}"
45
+ return facebook_sig_params
46
+ else
47
+ log "sig #{params['fb_sig']} invalid, should be #{calculate_sig(facebook_sig_params)}"
48
+ return nil
49
+ end
50
+ end
51
+
52
+ def calculate_sig(facebook_sig_params)
53
+ raw_string = facebook_sig_params.map{ |*args| args.join('=') }.sort.join
54
+ Digest::MD5.hexdigest([raw_string, @fb.secret].join)
55
+ end
56
+
57
+ def log(msg)
58
+ # puts("legacy_session/#{@fb.app_id} #{msg}")
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,54 @@
1
+ module FacebookClient
2
+
3
+ module Session
4
+
5
+ require 'digest'
6
+ require 'yajl'
7
+
8
+ class SessionParam < Base
9
+
10
+ def self.create_and_secure(fb, params)
11
+ iframe_session = new(fb, params)
12
+
13
+ iframe_session.secure? ? iframe_session : nil
14
+ end
15
+
16
+ def initialize(fb, params)
17
+ @fb=fb
18
+ @data=parse_fbs!(params["session"])
19
+ end
20
+
21
+ def parse_fbs!(fbs)
22
+ @data = fbs &&
23
+ check_sig_and_return_data(Yajl::Parser.parse(fbs))
24
+ end
25
+
26
+ def secure?
27
+ @data.is_a?(Hash) and @data.has_key?('uid')
28
+ end
29
+
30
+ def uid
31
+ @data['uid']
32
+ end
33
+
34
+ def access_token
35
+ @data["access_token"]
36
+ end
37
+
38
+ # private
39
+
40
+ def check_sig_and_return_data(params)
41
+ params if calculate_sig(params) == params['sig']
42
+ end
43
+
44
+ def calculate_sig(params)
45
+ args = params.reject{ |(k, v)| k == 'sig' }.sort.
46
+ map{ |a| a.join('=') }.join
47
+
48
+ Digest::MD5.hexdigest(args + @fb.secret)
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,91 @@
1
+ # http://developers.facebook.com/docs/authentication/canvas
2
+ # sample fb data from july 19, 2010
3
+ # {"fb_sig_app_id"=>"126995317325037", "signed_request"=>"XRVtkDu6T9Kre3nIcQXLlAdD8A8pW09QDxX_S1t1yJQ.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjAsIm9hdXRoX3Rva2VuIjoiMTI2OTk1MzE3MzI1MDM3fGViNmU2ZTczNGFlNjY0ZjMwMWQ4YTM3NS0xMDAwMDExNjU1MDczMTl8QlZxMER4MnVUVXdfTWUwbXkxQzBPLUZYYVNZLiIsInVzZXJfaWQiOiIxMDAwMDExNjU1MDczMTkifQ", "fb_sig_iframe_key"=>"98f13708210194c475687be6106a3b84", "fb_sig_locale"=>"en_US", "fb_sig_in_iframe"=>"1", "action"=>"index", "fb_sig"=>"0f9c16fe38b6507287a513070fc4882e", "fb_sig_in_new_facebook"=>"1", "fb_sig_added"=>"1", "fb_sig_country"=>"us", "fb_sig_ext_perms"=>"read_stream,status_update,photo_upload,video_upload,offline_access,email,create_note,share_item,publish_stream,user_photos,user_photo_video_tags,friends_photos,friends_photo_video_tags", "fb_sig_cookie_sig"=>"07eea766c8bdc363783472c34aea3cba", "fb_sig_session_key"=>"eb6e6e734ae664f301d8a375-100001165507319", "fb_sig_expires"=>"0", "fb_sig_ss"=>"cde1e8478e3f7d72960da3133091d6ae", "controller"=>"quizzes", "fb_sig_api_key"=>"12ad2dc78d9f6816ae50be94f93b571c", "fb_sig_user"=>"100001165507319", "fb_sig_profile_update_time"=>"1275440106", "fb_sig_time"=>"1279687778.633"}
4
+ # The signed_request parameter is the concatenation of
5
+ # a HMAC SHA-256 signature string, a period (.),
6
+ # and a base64url encoded JSON object.
7
+ # It looks something like this (without the newlines):
8
+ # vlXgu64BQGFSQrY0ZcJBZASMvYvTHu9GQ0YM9rjPSso
9
+ # .
10
+ # eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsIjAiOiJwYXlsb2FkIn0
11
+ module FacebookClient
12
+
13
+ module Session
14
+
15
+ require 'digest'
16
+ require 'digest/md5'
17
+ require 'yajl'
18
+ require 'base64'
19
+ require 'openssl'
20
+
21
+ class SignedRequestParam < Base
22
+
23
+ def self.create_and_secure(fb, params)
24
+ session = new(fb, params)
25
+
26
+ session.secure? ? session : nil
27
+ end
28
+
29
+ def initialize(fb, params)
30
+ @fb=fb
31
+ @data=parse_signed_request!(params["signed_request"])
32
+ end
33
+
34
+ def parse_signed_request!(str)
35
+ @data = str &&
36
+ check_sig_and_return_data(str, self.class.parse_params(str))
37
+ end
38
+
39
+ def secure?
40
+ @data.is_a?(Hash) and @data.has_key?('user_id')
41
+ end
42
+
43
+ def uid
44
+ @data['user_id']
45
+ end
46
+
47
+ def access_token
48
+ @data["oauth_token"]
49
+ end
50
+
51
+ # private
52
+
53
+ def check_sig_and_return_data(signed_request, params)
54
+ params if self.class.verify_signed_request(@fb.secret, signed_request)
55
+ end
56
+
57
+ def calculate_sig(params)
58
+ args = params.reject{ |(k, v)| k == 'sig' }.sort.
59
+ map{ |a| a.join('=') }.join
60
+
61
+ Digest::MD5.hexdigest(args + @fb.secret)
62
+ end
63
+
64
+ # looks like this:
65
+ # {"expires"=>0, "algorithm"=>"HMAC-SHA256", "user_id"=>"19392189382", "oauth_token"=>"some-token"}
66
+ def self.parse_params(signed_request)
67
+ encoded_url = signed_request.split(".").last
68
+ data = JSON.parse(base64_url_decode(encoded_url))
69
+ end
70
+
71
+ # This function takes the app secret and the signed request, and verifies if the request is valid.
72
+ def self.verify_signed_request(secret, signed_request)
73
+ signature, encoded_url = signed_request.split(".")
74
+ signature = base64_url_decode(signature)
75
+ expected_sig = OpenSSL::HMAC.digest('SHA256', secret, encoded_url.tr("-_", "+/"))
76
+ return signature == expected_sig
77
+ end
78
+
79
+ # Ruby's implementation of base64 decoding seems to be reading the string in multiples of 4 and ignoring
80
+ # any extra characters if there are no white-space characters at the end. Since facebook does not take this
81
+ # into account, this function fills any string with white spaces up to the point where it becomes divisible
82
+ # by 4, then it replaces '-' with '+' and '_' with '/' (URL-safe decoding), and decodes the result.
83
+ def self.base64_url_decode(str)
84
+ str = str + "=" * (4 - str.size % 4) unless str.size % 4 == 0
85
+ return Base64.decode64(str.tr("-_", "+/"))
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: facebook_client
3
3
  version: !ruby/object:Gem::Version
4
- hash: 91
4
+ hash: 95
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
9
  - 5
10
- - 0
11
- version: 0.0.5.0
10
+ - 2
11
+ version: 0.0.5.2
12
12
  platform: ruby
13
13
  authors:
14
14
  - David Crockett
@@ -77,13 +77,15 @@ extra_rdoc_files: []
77
77
 
78
78
  files:
79
79
  - lib/auth.rb
80
- - lib/cookie_session.rb
81
80
  - lib/ext.rb
82
81
  - lib/facebook_client.rb
83
82
  - lib/graph.rb
84
- - lib/iframe_session.rb
85
- - lib/legacy_session.rb
86
83
  - lib/rest_api.rb
84
+ - lib/session/base.rb
85
+ - lib/session/cookie.rb
86
+ - lib/session/fb_sig_param.rb
87
+ - lib/session/session_param.rb
88
+ - lib/session/signed_request_param.rb
87
89
  has_rdoc: true
88
90
  homepage:
89
91
  licenses: []
@@ -1,52 +0,0 @@
1
- module FacebookClient
2
-
3
- require 'rack'
4
- require 'digest'
5
-
6
- class CookieSession
7
-
8
- def self.create_and_secure(fb, cookies)
9
- cookie_session = new(fb, cookies)
10
-
11
- cookie_session.secure? ? cookie_session : nil
12
- end
13
-
14
- def initialize(fb, cookies)
15
- @fb=fb
16
- @data=parse_fbs!(cookies["fbs_#{fb.app_id}"])
17
- end
18
-
19
- def graph
20
- @graph ||= Graph.new(@fb, @data["access_token"], 0)
21
- @graph
22
- end
23
-
24
- def parse_fbs!(fbs)
25
- @data = fbs &&
26
- check_sig_and_return_data(Rack::Utils.parse_query(fbs[1..-2]))
27
- end
28
-
29
- def secure?
30
- @data.is_a?(Hash) and @data.has_key?('uid')
31
- end
32
-
33
- def uid
34
- @data['uid']
35
- end
36
-
37
- private
38
-
39
- def check_sig_and_return_data(cookies)
40
- cookies if calculate_sig(cookies) == cookies['sig']
41
- end
42
-
43
- def calculate_sig(cookies)
44
- args = cookies.reject{ |(k, v)| k == 'sig' }.sort.
45
- map{ |a| a.join('=') }.join
46
-
47
- Digest::MD5.hexdigest(args + @fb.secret)
48
- end
49
-
50
- end
51
-
52
- end
@@ -1,51 +0,0 @@
1
- module FacebookClient
2
-
3
- require 'digest'
4
- require 'yajl'
5
-
6
- class IframeSession
7
-
8
- def self.create_and_secure(fb, params)
9
- iframe_session = new(fb, params)
10
-
11
- iframe_session.secure? ? iframe_session : nil
12
- end
13
-
14
- def initialize(fb, params)
15
- @fb=fb
16
- @data=parse_fbs!(params["session"])
17
- end
18
-
19
- def parse_fbs!(fbs)
20
- @data = fbs &&
21
- check_sig_and_return_data(Yajl::Parser.parse(fbs))
22
- end
23
-
24
- def secure?
25
- @data.is_a?(Hash) and @data.has_key?('uid')
26
- end
27
-
28
- def graph
29
- @graph ||= Graph.new(@fb, @data["access_token"], 0)
30
- @graph
31
- end
32
-
33
- def uid
34
- @data['uid']
35
- end
36
-
37
- # private
38
-
39
- def check_sig_and_return_data(params)
40
- params if calculate_sig(params) == params['sig']
41
- end
42
-
43
- def calculate_sig(params)
44
- args = params.reject{ |(k, v)| k == 'sig' }.sort.
45
- map{ |a| a.join('=') }.join
46
-
47
- Digest::MD5.hexdigest(args + @fb.secret)
48
- end
49
-
50
- end
51
- end
@@ -1,60 +0,0 @@
1
- module FacebookClient
2
- require 'digest'
3
-
4
- class LegacySession
5
-
6
- def self.create_and_secure(fb, params)
7
- legacy_session = new(fb, params)
8
-
9
- legacy_session.secure? ? legacy_session : nil
10
- end
11
-
12
- def initialize(fb, params)
13
- @fb=fb
14
- @params=verfiy_params_and_return(params)
15
- end
16
-
17
- def secure?
18
- @params.is_a?(Hash) and @params.has_key?('user')
19
- end
20
-
21
- def uid
22
- @params['user']
23
- end
24
-
25
- def graph
26
- @graph ||= Graph.new(@fb, @params["session_key"], 0)
27
- @graph
28
- end
29
-
30
- def verfiy_params_and_return(params)
31
- if params['fb_sig'].nil? or !params['fb_sig'].is_a?(String)
32
- log 'missing fb_sig'
33
- return nil
34
- end
35
-
36
- facebook_sig_params = params.inject({}) do |collection, pair|
37
- collection[pair.first.sub(/^fb_sig_/, '')] = pair.last if pair.first[0,7] == 'fb_sig_'
38
- collection
39
- end
40
-
41
- if params['fb_sig']==calculate_sig(facebook_sig_params)
42
- log "secured for #{facebook_sig_params['user']}"
43
- return facebook_sig_params
44
- else
45
- log "sig #{params['fb_sig']} invalid, should be #{calculate_sig(facebook_sig_params)}"
46
- return nil
47
- end
48
- end
49
-
50
- def calculate_sig(facebook_sig_params)
51
- raw_string = facebook_sig_params.map{ |*args| args.join('=') }.sort.join
52
- Digest::MD5.hexdigest([raw_string, @fb.secret].join)
53
- end
54
-
55
- def log(msg)
56
- # puts("legacy_session/#{@fb.app_id} #{msg}")
57
- end
58
-
59
- end
60
- end