clickonchris-facebooker2 0.0.7.x1

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.
@@ -0,0 +1,50 @@
1
+ # Facebooker2
2
+ require "mogli"
3
+ module Facebooker2
4
+ class NotConfigured < Exception; end
5
+ class << self
6
+ attr_accessor :api_key, :secret, :app_id
7
+ end
8
+
9
+ def self.secret
10
+ @secret || raise_unconfigured_exception
11
+ end
12
+
13
+ def self.app_id
14
+ @app_id || raise_unconfigured_exception
15
+ end
16
+
17
+ def self.raise_unconfigured_exception
18
+ raise NotConfigured.new("No configuration provided for Facebooker2. Either set the app_id and secret or call Facebooker2.load_facebooker_yaml in an initializer")
19
+ end
20
+
21
+ def self.configuration=(hash)
22
+ self.api_key = hash[:api_key]
23
+ self.secret = hash[:secret]
24
+ self.app_id = hash[:app_id]
25
+ end
26
+
27
+ def self.load_facebooker_yaml
28
+ config = YAML.load(ERB.new(File.read(File.join(::Rails.root,"config","facebooker.yml"))).result)[::Rails.env]
29
+ raise NotConfigured.new("Unable to load configuration for #{::Rails.env} from facebooker.yml. Is it set up?") if config.nil?
30
+ self.configuration = config.with_indifferent_access
31
+ end
32
+
33
+ def self.cast_to_facebook_id(object)
34
+ if object.kind_of?(Mogli::Profile)
35
+ object.id
36
+ elsif object.respond_to?(:facebook_id)
37
+ object.facebook_id
38
+ else
39
+ object
40
+ end
41
+ end
42
+ end
43
+
44
+
45
+ require "facebooker2/rails/controller"
46
+ require "facebooker2/rails/helpers/facebook_connect"
47
+ require "facebooker2/rails/helpers/javascript"
48
+ require "facebooker2/rails/helpers/request_forms"
49
+ require "facebooker2/rails/helpers/user"
50
+ require "facebooker2/rails/helpers"
@@ -0,0 +1,4 @@
1
+ module Facebooker2
2
+ module Rails
3
+ end
4
+ end
@@ -0,0 +1,180 @@
1
+ require "digest/md5"
2
+ require "hmac-sha2"
3
+ module Facebooker2
4
+ module Rails
5
+ module Controller
6
+
7
+ def self.included(controller)
8
+ controller.helper Facebooker2::Rails::Helpers
9
+ controller.helper_method :current_facebook_user
10
+ controller.helper_method :current_facebook_client
11
+ controller.helper_method :facebook_params
12
+ end
13
+
14
+ def current_facebook_user
15
+ fetch_client_and_user
16
+ @_current_facebook_user
17
+ end
18
+
19
+ def current_facebook_client
20
+ fetch_client_and_user
21
+ @_current_facebook_client
22
+ end
23
+
24
+ # This mimics the getSession logic from the php facebook SDK
25
+ # https://github.com/facebook/php-sdk/blob/master/src/facebook.php#L333
26
+ #
27
+ def fetch_client_and_user
28
+ return if @_fb_user_fetched
29
+ # Try to authenticate from the signed request first
30
+ sig = fetch_client_and_user_from_signed_request
31
+ sig = fetch_client_and_user_from_cookie unless @_current_facebook_client
32
+
33
+ #write the authentication params to a new cookie
34
+ if !@_current_facebook_client.nil?
35
+ #we may have generated the signature based on the params in @facebook_params, and the expiration here is different
36
+
37
+ set_fb_cookie(@_current_facebook_client.access_token, @_current_facebook_client.expiration, @_current_facebook_user.id, sig)
38
+ else
39
+ # if we do not have a client, delete the cookie
40
+ set_fb_cookie(nil,nil,nil,nil)
41
+ end
42
+
43
+ @_fb_user_fetched = true
44
+ end
45
+
46
+ def fetch_client_and_user_from_cookie
47
+ if (hash_data = fb_cookie_hash) and
48
+ fb_cookie_signature_correct?(fb_cookie_hash,Facebooker2.secret)
49
+ fb_create_user_and_client(hash_data["access_token"],hash_data["expires"],hash_data["uid"])
50
+ return fb_cookie_hash["sig"]
51
+ end
52
+ end
53
+
54
+ def fb_create_user_and_client(token,expires,userid)
55
+ client = Mogli::Client.new(token,expires.to_i)
56
+ user = Mogli::User.new(:id=>userid)
57
+ fb_sign_in_user_and_client(user,client)
58
+ end
59
+
60
+ def fb_sign_in_user_and_client(user,client)
61
+ user.client = client
62
+ @_current_facebook_user = user
63
+ @_current_facebook_client = client
64
+ @_fb_user_fetched = true
65
+ end
66
+
67
+ def fb_cookie_hash
68
+ return nil unless fb_cookie?
69
+ hash={}
70
+ data = fb_cookie.gsub(/"/,"")
71
+ data.split("&").each do |str|
72
+ parts = str.split("=")
73
+ hash[parts.first] = parts.last
74
+ end
75
+ hash
76
+ end
77
+
78
+ def fb_cookie?
79
+ !fb_cookie.nil?
80
+ end
81
+
82
+ def fb_cookie
83
+ cookies[fb_cookie_name]
84
+ end
85
+
86
+ def fb_cookie_name
87
+ return "fbs_#{Facebooker2.app_id}"
88
+ end
89
+
90
+ # check if the expected signature matches the one from facebook
91
+ def fb_cookie_signature_correct?(hash,secret)
92
+ generateSignature(hash,secret) == hash["sig"]
93
+ end
94
+
95
+ # compute the md5 sig based on access_token,expires,uid, and the app secret
96
+ def generateSignature(hash,secret)
97
+ sorted_keys = hash.keys.reject {|k| k=="sig"}.sort
98
+ test_string = ""
99
+ sorted_keys.each do |key|
100
+ test_string += "#{key}=#{hash[key]}"
101
+ end
102
+ test_string += secret
103
+ sig = Digest::MD5.hexdigest(test_string)
104
+ return sig
105
+ end
106
+
107
+ def fb_signed_request_json(encoded)
108
+ chars_to_add = 4-(encoded.size % 4)
109
+ encoded += ("=" * chars_to_add)
110
+ Base64.decode64(encoded)
111
+ end
112
+
113
+ def facebook_params
114
+ @facebook_param ||= fb_load_facebook_params
115
+ end
116
+
117
+ def fb_load_facebook_params
118
+ return {} if params[:signed_request].blank?
119
+ sig,encoded_json = params[:signed_request].split(".")
120
+ return {} unless fb_signed_request_sig_valid?(sig,encoded_json)
121
+ ActiveSupport::JSON.decode(fb_signed_request_json(encoded_json)).with_indifferent_access
122
+ end
123
+
124
+ def fb_signed_request_sig_valid?(sig,encoded)
125
+ base64 = Base64.encode64(HMAC::SHA256.digest(Facebooker2.secret,encoded))
126
+ #now make the url changes that facebook makes
127
+ url_escaped_base64 = base64.gsub(/=*\n?$/,"").tr("+/","-_")
128
+ sig == url_escaped_base64
129
+ end
130
+
131
+ def fetch_client_and_user_from_signed_request
132
+ if facebook_params[:oauth_token]
133
+ fb_create_user_and_client(facebook_params[:oauth_token],facebook_params[:expires],facebook_params[:user_id])
134
+
135
+ if @_current_facebook_client
136
+ #compute a signature so we can store it in the cookie
137
+ sig_hash = Hash["uid"=>facebook_params[:user_id],"access_token"=>facebook_params[:oauth_token],"expires"=>facebook_params[:expires]]
138
+ return generateSignature(sig_hash, Facebooker2.secret)
139
+ end
140
+ end
141
+ end
142
+
143
+
144
+ # /**
145
+ # This method was shamelessly stolen from the php facebook SDK:
146
+ # https://github.com/facebook/php-sdk/blob/master/src/facebook.php
147
+ #
148
+ # Set a JS Cookie based on the _passed in_ session. It does not use the
149
+ # currently stored session -- you need to explicitly pass it in.
150
+ #
151
+ # If a nil access_token is passed in this method will actually delete the fbs_ cookie
152
+ #
153
+ # */
154
+ def set_fb_cookie(access_token,expires,uid,sig)
155
+
156
+ #default values for the cookie
157
+ value = 'deleted'
158
+ expires = Time.now.utc - 3600 unless expires != nil
159
+
160
+ if access_token
161
+ value = '"uid=' + uid + '&' +
162
+ 'access_token=' + access_token + '&' +
163
+ 'expires=' + expires.to_i.to_s + '&' +
164
+ 'sig=' + sig + '"'
165
+ end
166
+
167
+ # if an existing cookie is not set, we dont need to delete it
168
+ if (value == 'deleted' && cookies[fb_cookie_name] == "" )
169
+ return;
170
+ end
171
+
172
+ # in php they have to check if headers have already been sent before setting the cookie
173
+ # maybe rails we don't have this problem?
174
+
175
+ #My browser doesn't seem to save the cookie if I set expires
176
+ cookies[fb_cookie_name] = { :value=>value }#, :expires=>expires}
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,33 @@
1
+ module Facebooker2
2
+ module Rails
3
+ module Helpers
4
+ include FacebookConnect
5
+ include Javascript
6
+ include RequestForms
7
+ include User
8
+
9
+ def fb_stringify_vals(hash)
10
+ result={}
11
+ hash.each do |key,value|
12
+ result[key]=value.to_s
13
+ end
14
+ result
15
+ end
16
+ def fb_transform_keys(options,transformation_hash)
17
+ new_hash = {}
18
+ options.each do |key,value|
19
+ new_key = transformation_hash[key]||key
20
+ new_hash[new_key]=value
21
+ end
22
+ new_hash
23
+ end
24
+ FB_ALWAYS_VALID_OPTION_KEYS = [:class, :style]
25
+
26
+ def fb_assert_valid_keys(options,*valid_keys)
27
+ unknown_keys = options.keys - [valid_keys + FB_ALWAYS_VALID_OPTION_KEYS].flatten
28
+ raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,52 @@
1
+ module Facebooker2
2
+ module Rails
3
+ module Helpers
4
+ module FacebookConnect
5
+ #
6
+ # Render an <fb:login-button> element, similar to
7
+ # fb_login_button. Adds a js redirect to the onlogin event via rjs.
8
+ #
9
+ # ==== Examples
10
+ #
11
+ # fb_login_and_redirect '/other_page'
12
+ # => <fb:login-button onlogin="window.location.href = &quot;/other_page&quot;;"></fb:login-button>
13
+ #
14
+ # Like #fb_login_button, this also supports the :text option
15
+ #
16
+ # fb_login_and_redirect '/other_page', :text => "Login with Facebook", :v => '2'
17
+ # => <fb:login-button onlogin="window.location.href = &quot;/other_page&quot;;" v="2">Login with Facebook</fb:login-button>
18
+ #
19
+ def fb_login_and_redirect(url, options = {})
20
+ js = update_page do |page|
21
+ page.redirect_to url
22
+ end
23
+
24
+ text = options.delete(:text)
25
+
26
+ #rails 3 only escapes non-html_safe strings, so get the raw string instead of the SafeBuffer
27
+ content_tag("fb:login-button",text,options.merge(:onlogin=>js.to_str))
28
+ end
29
+
30
+ def fb_login(options = {},&proc)
31
+ js = capture(&proc)
32
+ text = options.delete(:text)
33
+ concat(content_tag("fb:login-button",text,options.merge(:onlogin=>js.to_str)))
34
+ end
35
+
36
+ #
37
+ # Logs the user out of facebook and redirects to the given URL
38
+ # args are passed to the call to link_to_function
39
+ def fb_logout_link(text,url,*args)
40
+ function= "FB.logout(function() {window.location.href = '#{url}';})"
41
+ link_to_function text, function.to_str, *args
42
+ end
43
+
44
+ def fb_server_fbml(style=nil,&proc)
45
+ style_string=" style=\"#{style}\"" if style
46
+ content = capture(&proc)
47
+ concat("<fb:serverFbml#{style_string}><script type='text/fbml'>#{content}</script></fb:serverFbml>")
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,56 @@
1
+ module Facebooker2
2
+ module Rails
3
+ module Helpers
4
+ module Javascript
5
+
6
+ def fb_html_safe(str)
7
+ if str.respond_to?(:html_safe)
8
+ str.html_safe
9
+ else
10
+ str
11
+ end
12
+ end
13
+
14
+ def fb_connect_async_js(app_id=Facebooker2.app_id,options={},&proc)
15
+ opts = Hash.new(true).merge!(options)
16
+ cookie = opts[:cookie]
17
+ status = opts[:status]
18
+ xfbml = opts[:xfbml]
19
+ extra_js = capture(&proc) if block_given?
20
+ js = <<-JAVASCRIPT
21
+ <script>
22
+ window.fbAsyncInit = function() {
23
+ FB.init({
24
+ appId : '#{app_id}',
25
+ status : #{status}, // check login status
26
+ cookie : #{cookie}, // enable cookies to allow the server to access the session
27
+ xfbml : #{xfbml} // parse XFBML
28
+ });
29
+ #{extra_js}
30
+ };
31
+
32
+ (function() {
33
+ var s = document.createElement('div');
34
+ s.setAttribute('id','fb-root');
35
+ document.documentElement.getElementsByTagName("body")[0].appendChild(s);
36
+ var e = document.createElement('script');
37
+ e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
38
+ e.async = true;
39
+ s.appendChild(e);
40
+ }());
41
+ </script>
42
+ JAVASCRIPT
43
+ escaped_js = fb_html_safe(js)
44
+ if block_given?
45
+ concat(escaped_js)
46
+ #return the empty string, since concat returns the buffer and we don't want double output
47
+ # from klochner
48
+ ""
49
+ else
50
+ escaped_js
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,33 @@
1
+ module Facebooker2
2
+ module Rails
3
+ module Helpers
4
+ module RequestForms
5
+ def fb_req_choice(label,url)
6
+ tag "fb:req-choice",:label=>label,:url=>url
7
+ end
8
+
9
+ def fb_multi_friend_selector(message,options={},&block)
10
+ options = fb_stringify_vals({:showborder=>false,:actiontext=>message,:max=>20}.merge(options.dup))
11
+ tag("fb:multi-friend-selector",options)
12
+ end
13
+
14
+ def fb_request_form(type,url,message,options={},&block)
15
+ content = capture(&block)
16
+ concat(content_tag("fb:request-form", content.to_s + fb_forgery_protection_token_tag,
17
+ {:action=>url,:method=>"post",:invite=>true,:type=>type,:content=>message}.merge(options)))
18
+ end
19
+
20
+
21
+ def fb_forgery_protection_token_tag
22
+ unless protect_against_forgery?
23
+ ''
24
+ else
25
+ tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
26
+ end
27
+ end
28
+
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,49 @@
1
+ module Facebooker2
2
+ module Rails
3
+ module Helpers
4
+ module User
5
+ # Render an fb:name tag for the given user
6
+ # This renders the name of the user specified. You can use this tag as both subject and object of
7
+ # a sentence. <em> See </em> http://wiki.developers.facebook.com/index.php/Fb:name for full description.
8
+ # Use this tag on FBML pages instead of retrieving the user's info and rendering the name explicitly.
9
+ #
10
+ def fb_name(user, options={})
11
+ options = fb_transform_keys(options,FB_NAME_OPTION_KEYS_TO_TRANSFORM)
12
+ fb_assert_valid_keys(options, FB_NAME_VALID_OPTION_KEYS)
13
+ options.merge!(:uid => Facebooker2.cast_to_facebook_id(user))
14
+ content_tag("fb:name",nil, fb_stringify_vals(options))
15
+ end
16
+
17
+ FB_NAME_OPTION_KEYS_TO_TRANSFORM = {:first_name_only => :firstnameonly,
18
+ :last_name_only => :lastnameonly,
19
+ :show_network => :shownetwork,
20
+ :use_you => :useyou,
21
+ :if_cant_see => :ifcantsee,
22
+ :subject_id => :subjectid}
23
+ FB_NAME_VALID_OPTION_KEYS = [:firstnameonly, :linked, :lastnameonly, :possessive, :reflexive,
24
+ :shownetwork, :useyou, :ifcantsee, :capitalize, :subjectid]
25
+
26
+
27
+ def fb_profile_pic(user, options={})
28
+ options = options.dup
29
+ validate_fb_profile_pic_size(options)
30
+ options = fb_transform_keys(options,FB_PROFILE_PIC_OPTION_KEYS_TO_TRANSFORM)
31
+ fb_assert_valid_keys(options,FB_PROFILE_PIC_VALID_OPTION_KEYS)
32
+ options.merge!(:uid => Facebooker2.cast_to_facebook_id(user))
33
+ content_tag("fb:profile-pic", nil,fb_stringify_vals(options))
34
+ end
35
+
36
+ FB_PROFILE_PIC_OPTION_KEYS_TO_TRANSFORM = {:facebook_logo => 'facebook-logo'}
37
+ FB_PROFILE_PIC_VALID_OPTION_KEYS = [:size, :linked, 'facebook-logo', :width, :height]
38
+ VALID_FB_PROFILE_PIC_SIZES = [:thumb, :small, :normal, :square]
39
+ def validate_fb_profile_pic_size(options)
40
+ if options.has_key?(:size) && !VALID_FB_PROFILE_PIC_SIZES.include?(options[:size].to_sym)
41
+ raise(ArgumentError, "Unknown value for size: #{options[:size]}")
42
+ end
43
+ end
44
+
45
+
46
+ end
47
+ end
48
+ end
49
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clickonchris-facebooker2
3
+ version: !ruby/object:Gem::Version
4
+ hash: 113
5
+ prerelease: 6
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 7
10
+ - x
11
+ - 1
12
+ version: 0.0.7.x1
13
+ platform: ruby
14
+ authors:
15
+ - Mike Mangino (patch by Chris Johnson)
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2011-01-27 00:00:00 -06:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ name: mogli
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ hash: 7
32
+ segments:
33
+ - 0
34
+ - 0
35
+ - 12
36
+ version: 0.0.12
37
+ type: :runtime
38
+ version_requirements: *id001
39
+ - !ruby/object:Gem::Dependency
40
+ name: ruby-hmac
41
+ prerelease: false
42
+ requirement: &id002 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ hash: 3
48
+ segments:
49
+ - 0
50
+ version: "0"
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ description: Facebook Connect integration library for ruby and rails
54
+ email: chris@clickonchris.com
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files: []
60
+
61
+ files:
62
+ - lib/facebooker2/rails/controller.rb
63
+ - lib/facebooker2/rails/helpers/facebook_connect.rb
64
+ - lib/facebooker2/rails/helpers/javascript.rb
65
+ - lib/facebooker2/rails/helpers/request_forms.rb
66
+ - lib/facebooker2/rails/helpers/user.rb
67
+ - lib/facebooker2/rails/helpers.rb
68
+ - lib/facebooker2/rails.rb
69
+ - lib/facebooker2.rb
70
+ has_rdoc: true
71
+ homepage: http://developers.facebook.com/docs/api
72
+ licenses: []
73
+
74
+ post_install_message:
75
+ rdoc_options: []
76
+
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">"
92
+ - !ruby/object:Gem::Version
93
+ hash: 25
94
+ segments:
95
+ - 1
96
+ - 3
97
+ - 1
98
+ version: 1.3.1
99
+ requirements: []
100
+
101
+ rubyforge_project:
102
+ rubygems_version: 1.4.2
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Facebook Connect integration library for ruby and rails
106
+ test_files: []
107
+