facebooker-lite 1.0.67

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.
Files changed (118) hide show
  1. data/.autotest +15 -0
  2. data/CHANGELOG.rdoc +24 -0
  3. data/COPYING.rdoc +19 -0
  4. data/Manifest.txt +114 -0
  5. data/README.rdoc +120 -0
  6. data/Rakefile +94 -0
  7. data/TODO.rdoc +4 -0
  8. data/facebooker.gemspec +42 -0
  9. data/generators/xd_receiver/templates/xd_receiver.html +10 -0
  10. data/generators/xd_receiver/templates/xd_receiver_ssl.html +10 -0
  11. data/generators/xd_receiver/xd_receiver_generator.rb +10 -0
  12. data/init.rb +25 -0
  13. data/install.rb +12 -0
  14. data/lib/facebooker.rb +261 -0
  15. data/lib/facebooker/adapters/adapter_base.rb +91 -0
  16. data/lib/facebooker/adapters/bebo_adapter.rb +77 -0
  17. data/lib/facebooker/adapters/facebook_adapter.rb +60 -0
  18. data/lib/facebooker/admin.rb +42 -0
  19. data/lib/facebooker/application.rb +37 -0
  20. data/lib/facebooker/attachment.rb +51 -0
  21. data/lib/facebooker/batch_request.rb +45 -0
  22. data/lib/facebooker/data.rb +57 -0
  23. data/lib/facebooker/feed.rb +78 -0
  24. data/lib/facebooker/logging.rb +44 -0
  25. data/lib/facebooker/mobile.rb +20 -0
  26. data/lib/facebooker/mock/service.rb +50 -0
  27. data/lib/facebooker/mock/session.rb +18 -0
  28. data/lib/facebooker/model.rb +139 -0
  29. data/lib/facebooker/models/affiliation.rb +10 -0
  30. data/lib/facebooker/models/album.rb +11 -0
  31. data/lib/facebooker/models/applicationproperties.rb +39 -0
  32. data/lib/facebooker/models/applicationrestrictions.rb +10 -0
  33. data/lib/facebooker/models/comment.rb +9 -0
  34. data/lib/facebooker/models/cookie.rb +10 -0
  35. data/lib/facebooker/models/education_info.rb +11 -0
  36. data/lib/facebooker/models/event.rb +28 -0
  37. data/lib/facebooker/models/family_relative_info.rb +7 -0
  38. data/lib/facebooker/models/friend_list.rb +16 -0
  39. data/lib/facebooker/models/group.rb +36 -0
  40. data/lib/facebooker/models/info_item.rb +10 -0
  41. data/lib/facebooker/models/info_section.rb +10 -0
  42. data/lib/facebooker/models/location.rb +8 -0
  43. data/lib/facebooker/models/message_thread.rb +89 -0
  44. data/lib/facebooker/models/notifications.rb +17 -0
  45. data/lib/facebooker/models/page.rb +46 -0
  46. data/lib/facebooker/models/photo.rb +19 -0
  47. data/lib/facebooker/models/tag.rb +12 -0
  48. data/lib/facebooker/models/user.rb +751 -0
  49. data/lib/facebooker/models/video.rb +9 -0
  50. data/lib/facebooker/models/work_info.rb +10 -0
  51. data/lib/facebooker/parser.rb +970 -0
  52. data/lib/facebooker/rails/backwards_compatible_param_checks.rb +31 -0
  53. data/lib/facebooker/rails/controller.rb +353 -0
  54. data/lib/facebooker/rails/extensions/action_controller.rb +47 -0
  55. data/lib/facebooker/rails/extensions/rack_setup.rb +16 -0
  56. data/lib/facebooker/rails/extensions/routing.rb +15 -0
  57. data/lib/facebooker/rails/facebook_pretty_errors.rb +22 -0
  58. data/lib/facebooker/rails/facebook_request_fix.rb +28 -0
  59. data/lib/facebooker/rails/facebook_request_fix_2-3.rb +31 -0
  60. data/lib/facebooker/rails/facebook_session_handling.rb +68 -0
  61. data/lib/facebooker/rails/facebook_url_rewriting.rb +60 -0
  62. data/lib/facebooker/rails/helpers/fb_connect.rb +75 -0
  63. data/lib/facebooker/rails/integration_session.rb +38 -0
  64. data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
  65. data/lib/facebooker/rails/publisher.rb +608 -0
  66. data/lib/facebooker/rails/routing.rb +49 -0
  67. data/lib/facebooker/rails/test_helpers.rb +68 -0
  68. data/lib/facebooker/rails/utilities.rb +22 -0
  69. data/lib/facebooker/server_cache.rb +24 -0
  70. data/lib/facebooker/service.rb +103 -0
  71. data/lib/facebooker/service/base_service.rb +19 -0
  72. data/lib/facebooker/service/curl_service.rb +44 -0
  73. data/lib/facebooker/service/net_http_service.rb +12 -0
  74. data/lib/facebooker/service/typhoeus_multi_service.rb +27 -0
  75. data/lib/facebooker/service/typhoeus_service.rb +17 -0
  76. data/lib/facebooker/session.rb +786 -0
  77. data/lib/facebooker/stream_post.rb +19 -0
  78. data/lib/facebooker/version.rb +9 -0
  79. data/lib/net/http_multipart_post.rb +123 -0
  80. data/lib/rack/facebook.rb +89 -0
  81. data/lib/rack/facebook_session.rb +21 -0
  82. data/lib/tasks/facebooker.rake +19 -0
  83. data/lib/tasks/facebooker.rb +2 -0
  84. data/lib/tasks/tunnel.rake +46 -0
  85. data/rails/init.rb +1 -0
  86. data/setup.rb +1585 -0
  87. data/templates/layout.erb +24 -0
  88. data/test/facebooker/adapters_test.rb +191 -0
  89. data/test/facebooker/admin_test.rb +102 -0
  90. data/test/facebooker/application_test.rb +110 -0
  91. data/test/facebooker/attachment_test.rb +72 -0
  92. data/test/facebooker/batch_request_test.rb +83 -0
  93. data/test/facebooker/data_test.rb +86 -0
  94. data/test/facebooker/logging_test.rb +43 -0
  95. data/test/facebooker/mobile_test.rb +45 -0
  96. data/test/facebooker/model_test.rb +133 -0
  97. data/test/facebooker/models/event_test.rb +15 -0
  98. data/test/facebooker/models/page_test.rb +56 -0
  99. data/test/facebooker/models/photo_test.rb +16 -0
  100. data/test/facebooker/models/user_test.rb +1074 -0
  101. data/test/facebooker/rails/facebook_request_fix_2-3_test.rb +25 -0
  102. data/test/facebooker/rails/facebook_url_rewriting_test.rb +76 -0
  103. data/test/facebooker/rails/integration_session_test.rb +13 -0
  104. data/test/facebooker/rails/publisher_test.rb +538 -0
  105. data/test/facebooker/rails_integration_test.rb +1543 -0
  106. data/test/facebooker/server_cache_test.rb +44 -0
  107. data/test/facebooker/service_test.rb +58 -0
  108. data/test/facebooker/session_test.rb +883 -0
  109. data/test/facebooker_test.rb +1263 -0
  110. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  111. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  112. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  113. data/test/net/http_multipart_post_test.rb +52 -0
  114. data/test/rack/facebook_session_test.rb +34 -0
  115. data/test/rack/facebook_test.rb +73 -0
  116. data/test/rails_test_helper.rb +36 -0
  117. data/test/test_helper.rb +74 -0
  118. metadata +278 -0
@@ -0,0 +1,31 @@
1
+ module Facebooker::Rails::BackwardsCompatibleParamChecks
2
+
3
+ def one_or_true( value )
4
+ case value
5
+ when String then
6
+ value == "1"
7
+ when Numeric then
8
+ value.to_f == 1.0
9
+ when TrueClass then
10
+ true
11
+ else
12
+ false
13
+ end
14
+ end
15
+
16
+ def zero_or_false( value )
17
+ case value
18
+ when String then
19
+ value.empty? || value == "0"
20
+ when Numeric then
21
+ value.to_f == 0.0
22
+ when FalseClass then
23
+ true
24
+ when NilClass then
25
+ true
26
+ else
27
+ false
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,353 @@
1
+ require 'facebooker'
2
+ require 'facebooker/rails/profile_publisher_extensions'
3
+ module Facebooker
4
+ module Rails
5
+ module Controller
6
+ include Facebooker::Rails::BackwardsCompatibleParamChecks
7
+ include Facebooker::Rails::ProfilePublisherExtensions
8
+ def self.included(controller)
9
+ controller.extend(ClassMethods)
10
+ controller.before_filter :set_facebook_request_format
11
+ controller.helper_attr :facebook_session_parameters
12
+ controller.helper_method :request_comes_from_facebook?
13
+ end
14
+
15
+ def initialize *args
16
+ @facebook_session = nil
17
+ @installation_required = nil
18
+ super
19
+ end
20
+
21
+ def facebook_session
22
+ @facebook_session
23
+ end
24
+
25
+ def facebook_session_parameters
26
+ {:fb_sig_session_key=>params[:fb_sig_session_key]}
27
+ end
28
+
29
+ def create_facebook_session
30
+ secure_with_facebook_params! || secure_with_cookies! || secure_with_token!
31
+ end
32
+
33
+ #this is used to proxy a connection through a rails app so the facebook secret key is not needed
34
+ #iphone apps use this
35
+ def create_facebook_session_with_secret
36
+ secure_with_session_secret!
37
+ end
38
+
39
+ def set_facebook_session
40
+ # first, see if we already have a session
41
+ session_set = session_already_secured?
42
+ # if not, see if we can load it from the environment
43
+ unless session_set
44
+ session_set = create_facebook_session
45
+ session[:facebook_session] = @facebook_session if session_set
46
+ end
47
+ if session_set
48
+ capture_facebook_friends_if_available!
49
+ Session.current = facebook_session
50
+ end
51
+ return session_set
52
+ end
53
+
54
+
55
+ def facebook_params
56
+ @facebook_params ||= verified_facebook_params
57
+ end
58
+
59
+ # Redirects the top window to the given url if the content is in an iframe, otherwise performs
60
+ # a normal redirect_to call.
61
+ def top_redirect_to(*args)
62
+ if request_is_facebook_iframe?
63
+ @redirect_url = url_for(*args)
64
+ render :layout => false, :inline => <<-HTML
65
+ <html><head>
66
+ <script type="text/javascript">
67
+ window.top.location.href = <%= @redirect_url.to_json -%>;
68
+ </script>
69
+ <noscript>
70
+ <meta http-equiv="refresh" content="0;url=<%=h @redirect_url %>" />
71
+ <meta http-equiv="window-target" content="_top" />
72
+ </noscript>
73
+ </head></html>
74
+ HTML
75
+ else
76
+ redirect_to(*args)
77
+ end
78
+ end
79
+
80
+ def redirect_to(*args)
81
+ if request_is_for_a_facebook_canvas? and !request_is_facebook_tab?
82
+ render :text => fbml_redirect_tag(*args)
83
+ else
84
+ super
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def session_already_secured?
91
+ (@facebook_session = session[:facebook_session]) && session[:facebook_session].secured? if valid_session_key_in_session?
92
+ end
93
+
94
+ def user_has_deauthorized_application?
95
+ # if we're inside the facebook session and there is no session key,
96
+ # that means the user revoked our access
97
+ # we don't want to keep using the old expired key from the cookie.
98
+ request_comes_from_facebook? and params[:fb_sig_session_key].blank?
99
+ end
100
+
101
+ def clear_facebook_session_information
102
+ session[:facebook_session] = nil
103
+ @facebook_session=nil
104
+ end
105
+
106
+ def valid_session_key_in_session?
107
+ #before we access the facebook_params, make sure we have the parameters
108
+ #otherwise we will blow up trying to access the secure parameters
109
+ if user_has_deauthorized_application?
110
+ clear_facebook_session_information
111
+ false
112
+ else
113
+ !session[:facebook_session].blank? && (params[:fb_sig_session_key].blank? || session[:facebook_session].session_key == facebook_params[:session_key])
114
+ end
115
+ end
116
+
117
+ def clear_fb_cookies!
118
+ domain_cookie_tag = "base_domain_#{Facebooker.api_key}"
119
+ cookie_domain = ".#{cookies[domain_cookie_tag]}" if cookies[domain_cookie_tag]
120
+ fb_cookie_names.each {|name| cookies.delete(name, :domain=>cookie_domain)}
121
+ cookies.delete Facebooker.api_key
122
+ end
123
+
124
+ def fb_cookie_prefix
125
+ Facebooker.api_key+"_"
126
+ end
127
+
128
+ def fb_cookie_names
129
+ fb_cookie_names = cookies.keys.select{|k| k && k.starts_with?(fb_cookie_prefix)}
130
+ end
131
+
132
+ def secure_with_cookies!
133
+ parsed = {}
134
+
135
+ fb_cookie_names.each { |key| parsed[key[fb_cookie_prefix.size,key.size]] = cookies[key] }
136
+
137
+ #returning gracefully if the cookies aren't set or have expired
138
+ return unless parsed['session_key'] && parsed['user'] && parsed['expires'] && parsed['ss']
139
+ return unless (Time.at(parsed['expires'].to_s.to_f) > Time.now) || (parsed['expires'] == "0")
140
+ #if we have the unexpired cookies, we'll throw an exception if the sig doesn't verify
141
+ verify_signature(parsed,cookies[Facebooker.api_key], true)
142
+
143
+ @facebook_session = new_facebook_session
144
+ @facebook_session.secure_with!(parsed['session_key'],parsed['user'],parsed['expires'],parsed['ss'])
145
+ @facebook_session
146
+ end
147
+
148
+ def secure_with_token!
149
+ if params['auth_token']
150
+ @facebook_session = new_facebook_session
151
+ @facebook_session.auth_token = params['auth_token']
152
+ @facebook_session.secure!
153
+ @facebook_session
154
+ end
155
+ end
156
+
157
+ def secure_with_session_secret!
158
+ if params['auth_token']
159
+ @facebook_session = new_facebook_session
160
+ @facebook_session.auth_token = params['auth_token']
161
+ @facebook_session.secure_with_session_secret!
162
+ @facebook_session
163
+ end
164
+ end
165
+
166
+ def secure_with_facebook_params!
167
+ return unless request_comes_from_facebook?
168
+
169
+ if ['user', 'session_key'].all? {|element| facebook_params[element]}
170
+ @facebook_session = new_facebook_session
171
+ @facebook_session.secure_with!(facebook_params['session_key'], facebook_params['user'], facebook_params['expires'])
172
+ @facebook_session
173
+ end
174
+ end
175
+
176
+ #override to specify where the user should be sent after logging in
177
+ def after_facebook_login_url
178
+ nil
179
+ end
180
+
181
+ def default_after_facebook_login_url
182
+ omit_keys = ["_method", "format"]
183
+ options = (params||{}).clone
184
+ options = options.reject{|k,v| k.to_s.match(/^fb_sig/) or omit_keys.include?(k.to_s)}
185
+ options = options.merge({:only_path => false})
186
+ url_for(options)
187
+ end
188
+
189
+ def create_new_facebook_session_and_redirect!
190
+ session[:facebook_session] = new_facebook_session
191
+ next_url = after_facebook_login_url || default_after_facebook_login_url
192
+ top_redirect_to session[:facebook_session].login_url({:next => next_url, :canvas=>params[:fb_sig_in_canvas]}) unless @installation_required
193
+ false
194
+ end
195
+
196
+ def new_facebook_session
197
+ Facebooker::Session.create(Facebooker.api_key, Facebooker.secret_key)
198
+ end
199
+
200
+ def capture_facebook_friends_if_available!
201
+ return unless request_comes_from_facebook?
202
+ if friends = facebook_params['friends']
203
+ facebook_session.user.friends = friends.map do |friend_uid|
204
+ User.new(friend_uid, facebook_session)
205
+ end
206
+ end
207
+ end
208
+
209
+ def verified_facebook_params
210
+ facebook_sig_params = params.inject({}) do |collection, pair|
211
+ collection[pair.first.sub(/^fb_sig_/, '')] = pair.last if pair.first[0,7] == 'fb_sig_'
212
+ collection
213
+ end
214
+ verify_signature(facebook_sig_params,params['fb_sig'])
215
+
216
+ facebook_sig_params.inject(HashWithIndifferentAccess.new) do |collection, pair|
217
+ collection[pair.first] = facebook_parameter_conversions[pair.first].call(pair.last)
218
+ collection
219
+ end
220
+ end
221
+
222
+ def earliest_valid_session
223
+ 48.hours.ago
224
+ end
225
+
226
+ def verify_signature(facebook_sig_params,expected_signature,force=false)
227
+ # Don't verify the signature if rack has already done so.
228
+ unless ::Rails.version >= "2.3" and ActionController::Dispatcher.middleware.include? Rack::Facebook and !force
229
+ raw_string = facebook_sig_params.map{ |*args| args.join('=') }.sort.join
230
+ actual_sig = Digest::MD5.hexdigest([raw_string, Facebooker::Session.secret_key].join)
231
+ raise Facebooker::Session::IncorrectSignature if actual_sig != expected_signature
232
+ end
233
+ raise Facebooker::Session::SignatureTooOld if facebook_sig_params['time'] && Time.at(facebook_sig_params['time'].to_f) < earliest_valid_session
234
+ true
235
+ end
236
+
237
+ def facebook_parameter_conversions
238
+ @facebook_parameter_conversions ||= Hash.new do |hash, key|
239
+ lambda{|value| value}
240
+ end.merge(
241
+ 'time' => lambda{|value| Time.at(value.to_f)},
242
+ 'in_canvas' => lambda{|value| one_or_true(value)},
243
+ 'added' => lambda{|value| one_or_true(value)},
244
+ 'expires' => lambda{|value| zero_or_false(value) ? nil : Time.at(value.to_f)},
245
+ 'friends' => lambda{|value| value.split(/,/)}
246
+ )
247
+ end
248
+
249
+ def fbml_redirect_tag(url,*args)
250
+ "<fb:redirect url=\"#{url_for(url)}\" />"
251
+ end
252
+
253
+ def request_comes_from_facebook?
254
+ request_is_for_a_facebook_canvas? || request_is_facebook_ajax? || request_is_fb_ping?
255
+ end
256
+
257
+ def request_is_fb_ping?
258
+ !params['fb_sig'].blank?
259
+ end
260
+
261
+ def request_is_for_a_facebook_canvas?
262
+ !params['fb_sig_in_canvas'].blank?
263
+ end
264
+
265
+ def request_is_facebook_tab?
266
+ !params["fb_sig_in_profile_tab"].blank?
267
+ end
268
+
269
+ def request_is_facebook_iframe?
270
+ !params["fb_sig_in_iframe"].blank?
271
+ end
272
+
273
+ def request_is_facebook_ajax?
274
+ one_or_true(params["fb_sig_is_mockajax"]) || one_or_true(params["fb_sig_is_ajax"])
275
+ end
276
+
277
+ def xml_http_request?
278
+ request_is_facebook_ajax? || super
279
+ end
280
+
281
+ def application_is_installed?
282
+ facebook_params['added']
283
+ end
284
+
285
+ def ensure_has_status_update
286
+ has_extended_permission?("status_update") || application_needs_permission("status_update")
287
+ end
288
+ def ensure_has_photo_upload
289
+ has_extended_permission?("photo_upload") || application_needs_permission("photo_upload")
290
+ end
291
+ def ensure_has_video_upload
292
+ has_extended_permission?("video_upload") || application_needs_permission("video_upload")
293
+ end
294
+ def ensure_has_create_listing
295
+ has_extended_permission?("create_listing") || application_needs_permission("create_listing")
296
+ end
297
+ def ensure_has_create_event
298
+ has_extended_permission?("create_event") || application_needs_permission("create_event")
299
+ end
300
+
301
+ def application_needs_permission(perm)
302
+ top_redirect_to(facebook_session.permission_url(perm))
303
+ end
304
+
305
+ def has_extended_permission?(perm)
306
+ params["fb_sig_ext_perms"] and params["fb_sig_ext_perms"].include?(perm)
307
+ end
308
+
309
+ def ensure_authenticated_to_facebook
310
+ set_facebook_session || create_new_facebook_session_and_redirect!
311
+ end
312
+
313
+ def ensure_application_is_installed_by_facebook_user
314
+ @installation_required = true
315
+ returning ensure_authenticated_to_facebook && application_is_installed? do |authenticated_and_installed|
316
+ application_is_not_installed_by_facebook_user unless authenticated_and_installed
317
+ end
318
+ end
319
+
320
+ def application_is_not_installed_by_facebook_user
321
+ next_url = after_facebook_login_url || default_after_facebook_login_url
322
+ top_redirect_to session[:facebook_session].install_url({:next => next_url})
323
+ end
324
+
325
+ def set_facebook_request_format
326
+ if request_is_facebook_ajax?
327
+ request.format = :fbjs
328
+ elsif request_comes_from_facebook? && !request_is_facebook_iframe?
329
+ request.format = :fbml
330
+ end
331
+ end
332
+
333
+
334
+ module ClassMethods
335
+ #
336
+ # Creates a filter which reqires a user to have already authenticated to
337
+ # Facebook before executing actions. Accepts the same optional options hash which
338
+ # before_filter and after_filter accept.
339
+ def ensure_authenticated_to_facebook(options = {})
340
+ before_filter :ensure_authenticated_to_facebook, options
341
+ end
342
+
343
+ def ensure_application_is_installed_by_facebook_user(options = {})
344
+ before_filter :ensure_application_is_installed_by_facebook_user, options
345
+ end
346
+
347
+ def request_comes_from_facebook?
348
+ request_is_for_a_facebook_canvas? || request_is_facebook_ajax?
349
+ end
350
+ end
351
+ end
352
+ end
353
+ end
@@ -0,0 +1,47 @@
1
+ module ::ActionController
2
+ class Base
3
+ def self.inherited_with_facebooker(subclass)
4
+ inherited_without_facebooker(subclass)
5
+ if subclass.to_s == "ApplicationController"
6
+ subclass.send(:include,Facebooker::Rails::Controller)
7
+ end
8
+ end
9
+ class << self
10
+ alias_method_chain :inherited, :facebooker
11
+ end
12
+ end
13
+ end
14
+
15
+
16
+ # When making get requests, Facebook sends fb_sig parameters both in the query string
17
+ # and also in the post body. We want to ignore the query string ones because they are one
18
+ # request out of date
19
+ # We only do thise when there are POST parameters so that IFrame linkage still works
20
+ if Rails.version < '2.3'
21
+ class ActionController::AbstractRequest
22
+ def query_parameters_with_facebooker
23
+ if request_parameters.blank?
24
+ query_parameters_without_facebooker
25
+ else
26
+ (query_parameters_without_facebooker||{}).reject {|key,value| key.to_s =~ /^fb_sig/}
27
+ end
28
+ end
29
+
30
+ alias_method_chain :query_parameters, :facebooker
31
+ end
32
+ else
33
+ class ActionController::Request
34
+ def query_parameters_with_facebooker
35
+ if request_parameters.blank?
36
+ query_parameters_without_facebooker
37
+ else
38
+ (query_parameters_without_facebooker||{}).reject {|key,value| key.to_s =~ /^fb_sig/}
39
+ end
40
+ end
41
+
42
+ alias_method_chain :query_parameters, :facebooker
43
+ end
44
+ end
45
+
46
+ Mime::Type.register_alias "text/html", :fbml
47
+ Mime::Type.register_alias "text/javascript", :fbjs
@@ -0,0 +1,16 @@
1
+ # Somewhere in 2.3 RewindableInput was removed- rack supports it natively
2
+ require 'rack/facebook'
3
+ require 'rack/facebook_session'
4
+
5
+ ActionController::Dispatcher.middleware.insert_before(
6
+ ActionController::ParamsParser,
7
+ Rack::Facebook
8
+ )
9
+
10
+ #use this if you aren't using the cookie store and want to use
11
+ # the facebook session key for your session id
12
+ # ActionController::Dispatcher.middleware.insert_before(
13
+ # ActionController::Base.session_store,
14
+ # Rack::FacebookSession,
15
+ # ActionController::Base.session_options[:key]
16
+ # )