facebook_client 0.0.5.0 → 0.0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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