rest-more 0.7.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.
Files changed (81) hide show
  1. data/.gitignore +6 -0
  2. data/.gitmodules +3 -0
  3. data/.travis.yml +13 -0
  4. data/CHANGES.md +7 -0
  5. data/Gemfile +26 -0
  6. data/LICENSE +201 -0
  7. data/README.md +72 -0
  8. data/Rakefile +63 -0
  9. data/TODO.md +14 -0
  10. data/example/rails2/Gemfile +21 -0
  11. data/example/rails2/README +4 -0
  12. data/example/rails2/Rakefile +11 -0
  13. data/example/rails2/app/controllers/application_controller.rb +134 -0
  14. data/example/rails2/app/views/application/helper.html.erb +2 -0
  15. data/example/rails2/config/boot.rb +130 -0
  16. data/example/rails2/config/environment.rb +15 -0
  17. data/example/rails2/config/environments/development.rb +17 -0
  18. data/example/rails2/config/environments/production.rb +28 -0
  19. data/example/rails2/config/environments/test.rb +30 -0
  20. data/example/rails2/config/initializers/cookie_verification_secret.rb +7 -0
  21. data/example/rails2/config/initializers/new_rails_defaults.rb +21 -0
  22. data/example/rails2/config/initializers/session_store.rb +15 -0
  23. data/example/rails2/config/preinitializer.rb +23 -0
  24. data/example/rails2/config/rest-core.yaml +16 -0
  25. data/example/rails2/config/routes.rb +43 -0
  26. data/example/rails2/log +0 -0
  27. data/example/rails2/test/functional/application_controller_test.rb +219 -0
  28. data/example/rails2/test/test_helper.rb +18 -0
  29. data/example/rails2/test/unit/rails_util_test.rb +44 -0
  30. data/example/rails3/Gemfile +20 -0
  31. data/example/rails3/README +4 -0
  32. data/example/rails3/Rakefile +7 -0
  33. data/example/rails3/app/controllers/application_controller.rb +134 -0
  34. data/example/rails3/app/views/application/helper.html.erb +2 -0
  35. data/example/rails3/config.ru +4 -0
  36. data/example/rails3/config/application.rb +23 -0
  37. data/example/rails3/config/boot.rb +6 -0
  38. data/example/rails3/config/environment.rb +5 -0
  39. data/example/rails3/config/environments/development.rb +23 -0
  40. data/example/rails3/config/environments/production.rb +49 -0
  41. data/example/rails3/config/environments/test.rb +30 -0
  42. data/example/rails3/config/initializers/secret_token.rb +7 -0
  43. data/example/rails3/config/initializers/session_store.rb +8 -0
  44. data/example/rails3/config/rest-core.yaml +16 -0
  45. data/example/rails3/config/routes.rb +5 -0
  46. data/example/rails3/test/functional/application_controller_test.rb +219 -0
  47. data/example/rails3/test/test_helper.rb +18 -0
  48. data/example/rails3/test/unit/rails_util_test.rb +44 -0
  49. data/example/sinatra/config.ru +16 -0
  50. data/lib/rest-core/client/facebook.rb +265 -0
  51. data/lib/rest-core/client/facebook/rails_util.rb +334 -0
  52. data/lib/rest-core/client/flurry.rb +107 -0
  53. data/lib/rest-core/client/flurry/rails_util.rb +74 -0
  54. data/lib/rest-core/client/github.rb +18 -0
  55. data/lib/rest-core/client/linkedin.rb +59 -0
  56. data/lib/rest-core/client/mixi.rb +47 -0
  57. data/lib/rest-core/client/simple.rb +2 -0
  58. data/lib/rest-core/client/twitter.rb +101 -0
  59. data/lib/rest-core/client/universal.rb +18 -0
  60. data/lib/rest-more.rb +11 -0
  61. data/lib/rest-more/version.rb +4 -0
  62. data/rest-more.gemspec +127 -0
  63. data/task/.gitignore +1 -0
  64. data/task/gemgem.rb +265 -0
  65. data/test/client/facebook/config/rest-core.yaml +8 -0
  66. data/test/client/facebook/test_api.rb +97 -0
  67. data/test/client/facebook/test_cache.rb +58 -0
  68. data/test/client/facebook/test_default.rb +23 -0
  69. data/test/client/facebook/test_error.rb +65 -0
  70. data/test/client/facebook/test_handler.rb +84 -0
  71. data/test/client/facebook/test_load_config.rb +39 -0
  72. data/test/client/facebook/test_misc.rb +72 -0
  73. data/test/client/facebook/test_oauth.rb +38 -0
  74. data/test/client/facebook/test_old.rb +114 -0
  75. data/test/client/facebook/test_page.rb +106 -0
  76. data/test/client/facebook/test_parse.rb +166 -0
  77. data/test/client/facebook/test_serialize.rb +43 -0
  78. data/test/client/facebook/test_timeout.rb +22 -0
  79. data/test/client/flurry/test_metrics.rb +83 -0
  80. data/test/client/twitter/test_api.rb +37 -0
  81. metadata +155 -0
@@ -0,0 +1,16 @@
1
+
2
+ require 'sinatra'
3
+ require 'rest-core'
4
+
5
+ app_id = '123'
6
+ secret = 'abc'
7
+ config = {:app_id => app_id,
8
+ :secret => secret}
9
+
10
+ post '/' do
11
+ fb = RestCore::Facebook.new(config)
12
+ fb.parse_signed_request!(params['signed_request'])
13
+ "#{fb.get('me').inspect.gsub('<', '&lt;')}\n"
14
+ end
15
+
16
+ run Sinatra::Application
@@ -0,0 +1,265 @@
1
+
2
+ require 'rest-core'
3
+ require 'rest-core/util/hmac'
4
+
5
+ RestCore::Facebook = RestCore::Builder.client(
6
+ :data, :app_id, :secret, :old_site) do
7
+
8
+ s = self.class # this is only for ruby 1.8!
9
+ use s::Timeout , 10
10
+
11
+ use s::DefaultSite , 'https://graph.facebook.com/'
12
+ use s::DefaultHeaders, {'Accept' => 'application/json',
13
+ 'Accept-Language' => 'en-us'}
14
+ use s::Oauth2Query , nil
15
+
16
+ use s::CommonLogger , nil
17
+ use s::Cache , nil, 600 do
18
+ use s::ErrorHandler, lambda{ |env|
19
+ raise ::RestCore::Facebook::Error.call(env) }
20
+ use s::ErrorDetector, lambda{ |env|
21
+ if env[s::RESPONSE_BODY].kind_of?(Hash)
22
+ env[s::RESPONSE_BODY]['error'] ||
23
+ env[s::RESPONSE_BODY]['error_code']
24
+ end}
25
+
26
+ use s::JsonDecode , true
27
+ end
28
+
29
+ use s::Defaults , :data => lambda{{}},
30
+ :old_site => 'https://api.facebook.com/'
31
+ end
32
+
33
+ class RestCore::Facebook::Error < RestCore::Error
34
+ include RestCore
35
+ class AccessToken < Facebook::Error; end
36
+ class InvalidAccessToken < AccessToken ; end
37
+ class MissingAccessToken < AccessToken ; end
38
+
39
+ attr_reader :error, :url
40
+ def initialize error, url=''
41
+ @error, @url = error, url
42
+ super("#{error.inspect} from #{url}")
43
+ end
44
+
45
+ def self.call env
46
+ error, url = env[RESPONSE_BODY], Middleware.request_uri(env)
47
+ return new(env[FAIL], url) unless error.kind_of?(Hash)
48
+ if invalid_token?(error)
49
+ InvalidAccessToken.new(error, url)
50
+ elsif missing_token?(error)
51
+ MissingAccessToken.new(error, url)
52
+ else
53
+ new(error, url)
54
+ end
55
+ end
56
+
57
+ def self.invalid_token? error
58
+ (%w[OAuthInvalidTokenException
59
+ OAuthException].include?((error['error'] || {})['type'])) ||
60
+ (error['error_code'] == 190) # Invalid OAuth 2.0 Access Token
61
+ end
62
+
63
+ def self.missing_token? error
64
+ (error['error'] || {})['message'] =~ /^An active access token/ ||
65
+ (error['error_code'] == 104) # Requires valid signature
66
+ end
67
+ end
68
+
69
+ module RestCore::Facebook::Client
70
+ include RestCore
71
+
72
+ def access_token
73
+ data['access_token'] || data['oauth_token'] if data.kind_of?(Hash)
74
+ end
75
+
76
+ def access_token= token
77
+ data['access_token'] = token if data.kind_of?(Hash)
78
+ end
79
+
80
+ def secret_access_token; "#{app_id}|#{secret}" ; end
81
+ def accept ; headers['Accept'] ; end
82
+ def accept= val; headers['Accept'] = val; end
83
+ def lang ; headers['Accept-Language'] ; end
84
+ def lang= val; headers['Accept-Language'] = val; end
85
+
86
+ def authorized? ; !!access_token ; end
87
+
88
+ def next_page hash, opts={}, &cb
89
+ if hash['paging'].kind_of?(Hash) && hash['paging']['next']
90
+ get(hash['paging']['next'], {}, opts, &cb)
91
+ else
92
+ yield(nil) if block_given?
93
+ end
94
+ end
95
+
96
+ def prev_page hash, opts={}, &cb
97
+ if hash['paging'].kind_of?(Hash) && hash['paging']['previous']
98
+ get(hash['paging']['previous'], {}, opts, &cb)
99
+ else
100
+ yield(nil) if block_given?
101
+ end
102
+ end
103
+ alias_method :previous_page, :prev_page
104
+
105
+ def for_pages hash, pages=1, opts={}, kind=:next_page, &cb
106
+ if pages > 1
107
+ merge_data(send(kind, hash, opts){ |result|
108
+ yield(result.freeze) if block_given?
109
+ for_pages(result, pages - 1, opts, kind, &cb) if result
110
+ }, hash)
111
+ else
112
+ yield(nil) if block_given?
113
+ hash
114
+ end
115
+ end
116
+
117
+ # cookies, app_id, secrect related below
118
+
119
+ def parse_rack_env! env
120
+ env['HTTP_COOKIE'].to_s =~ /fbs_#{app_id}=([^\;]+)/
121
+ self.data = parse_fbs!($1)
122
+ end
123
+
124
+ def parse_cookies! cookies
125
+ self.data = if fbsr = cookies["fbsr_#{app_id}"]
126
+ parse_fbsr!(fbsr)
127
+ else fbs = cookies["fbs_#{app_id}"]
128
+ parse_fbs!(fbs)
129
+ end
130
+ end
131
+
132
+ def parse_fbs! fbs
133
+ self.data = check_sig_and_return_data(
134
+ # take out facebook sometimes there but sometimes not quotes in cookies
135
+ Vendor.parse_query(fbs.to_s.sub(/^"/, '').sub(/"$/, '')))
136
+ end
137
+
138
+ def parse_fbsr! fbsr
139
+ old_data = parse_signed_request!(fbsr)
140
+ # beware! maybe facebook would take out the code someday
141
+ return self.data = old_data unless old_data && old_data['code']
142
+ # passing empty redirect_uri is needed!
143
+ authorize!(:code => old_data['code'], :redirect_uri => '')
144
+ self.data = old_data.merge(data)
145
+ end
146
+
147
+ def parse_json! json
148
+ self.data = json &&
149
+ check_sig_and_return_data(JsonDecode.json_decode(json))
150
+ rescue JsonDecode::ParseError
151
+ self.data = nil
152
+ end
153
+
154
+ def fbs
155
+ "#{fbs_without_sig(data).join('&')}&sig=#{calculate_sig(data)}"
156
+ end
157
+
158
+ # facebook's new signed_request...
159
+
160
+ def parse_signed_request! request
161
+ sig_encoded, json_encoded = request.split('.')
162
+ return self.data = nil unless sig_encoded && json_encoded
163
+ sig, json = [sig_encoded, json_encoded].map{ |str|
164
+ "#{str.tr('-_', '+/')}==".unpack('m').first
165
+ }
166
+ self.data = check_sig_and_return_data(
167
+ JsonDecode.json_decode(json).merge('sig' => sig)){
168
+ Hmac.sha256(secret, json_encoded)
169
+ }
170
+ rescue JsonDecode::ParseError
171
+ self.data = nil
172
+ end
173
+
174
+ # oauth related
175
+
176
+ def authorize_url opts={}
177
+ url('oauth/authorize',
178
+ {:client_id => app_id, :access_token => nil}.merge(opts))
179
+ end
180
+
181
+ def authorize! opts={}
182
+ query = {:client_id => app_id, :client_secret => secret}.merge(opts)
183
+ self.data = Vendor.parse_query(
184
+ get(url('oauth/access_token'), query,
185
+ {:json_decode => false}.merge(opts)))
186
+ end
187
+
188
+ # old rest facebook api, i will definitely love to remove them someday
189
+
190
+ def old_rest path, query={}, opts={}, &cb
191
+ uri = url("method/#{path}", {:format => 'json'}.merge(query),
192
+ {:site => old_site}.merge(opts))
193
+ if opts[:post]
194
+ post(url("method/#{path}", {:format => 'json'},
195
+ {:site => old_site}.merge(opts)),
196
+ query,
197
+ {} ,
198
+ opts.merge('cache.key' => uri, 'cache.post' => true),
199
+ &cb)
200
+ else
201
+ get(uri, {}, opts, &cb)
202
+ end
203
+ end
204
+
205
+ def secret_old_rest path, query={}, opts={}, &cb
206
+ old_rest(path, query, {:secret => true}.merge(opts), &cb)
207
+ end
208
+
209
+ def fql code, query={}, opts={}, &cb
210
+ old_rest('fql.query', {:query => code}.merge(query), opts, &cb)
211
+ end
212
+
213
+ def fql_multi codes, query={}, opts={}, &cb
214
+ old_rest('fql.multiquery',
215
+ {:queries => JsonDecode.json_encode(codes)}.merge(query), opts, &cb)
216
+ end
217
+
218
+ def exchange_sessions query={}, opts={}, &cb
219
+ q = {:client_id => app_id, :client_secret => secret,
220
+ :type => 'client_cred'}.merge(query)
221
+ post(url('oauth/exchange_sessions', q),
222
+ {}, {}, opts, &cb)
223
+ end
224
+
225
+ protected
226
+ def build_env env={}
227
+ super(env.inject({}){ |r, (k, v)|
228
+ case k.to_s
229
+ when 'secret' ; r['access_token'] = secret_access_token
230
+ when 'cache' ; r['cache.update'] = !!!v
231
+ else ; r[k.to_s] = v
232
+ end
233
+ r
234
+ })
235
+ end
236
+
237
+ def check_sig_and_return_data cookies
238
+ cookies if secret && if block_given?
239
+ yield
240
+ else
241
+ calculate_sig(cookies)
242
+ end == cookies['sig']
243
+ end
244
+
245
+ def calculate_sig cookies
246
+ Digest::MD5.hexdigest(fbs_without_sig(cookies).join + secret)
247
+ end
248
+
249
+ def fbs_without_sig cookies
250
+ cookies.reject{ |(k, v)| k == 'sig' }.sort.map{ |a| a.join('=') }
251
+ end
252
+
253
+ def merge_data lhs, rhs
254
+ [lhs, rhs].each{ |hash|
255
+ return rhs.reject{ |k, v| k == 'paging' } if
256
+ !hash.kind_of?(Hash) || !hash['data'].kind_of?(Array)
257
+ }
258
+ lhs['data'].unshift(*rhs['data'])
259
+ lhs
260
+ end
261
+ end
262
+
263
+ RestCore::Facebook.send(:include, RestCore::Facebook::Client)
264
+ require 'rest-core/client/facebook/rails_util' if
265
+ Object.const_defined?(:Rails)
@@ -0,0 +1,334 @@
1
+
2
+ require 'rest-core/util/rails_util_util'
3
+
4
+ require 'cgi'
5
+ require 'uri'
6
+
7
+ module RestCore::Facebook::DefaultAttributes
8
+ def default_log_method ; Rails.logger.method(:debug); end
9
+ def default_cache ; Rails.cache ; end
10
+ def default_canvas ; '' ; end
11
+ def default_iframe ; false ; end
12
+ def default_auto_authorize ; false ; end
13
+ def default_auto_authorize_options; {} ; end
14
+ def default_auto_authorize_scope ; '' ; end
15
+ def default_ensure_authorized ; false ; end
16
+ def default_write_session ; false ; end
17
+ def default_write_cookies ; false ; end
18
+ def default_write_handler ; nil ; end
19
+ def default_check_handler ; nil ; end
20
+ end
21
+
22
+ module RestCore::Facebook::RailsUtil
23
+ def self.init app=Rails
24
+ RestCore::Config.load_for_rails(RestCore::Facebook, 'facebook', app)
25
+ end
26
+
27
+ module Helper
28
+ def rc_facebook
29
+ controller.send(:rc_facebook)
30
+ end
31
+ end
32
+
33
+ def self.included controller
34
+ # skip if included already, any better way to detect this?
35
+ return if controller.respond_to?(:rc_facebook, true)
36
+
37
+ controller.rescue_from(RestCore::Facebook::Error::AccessToken,
38
+ :with => :rc_facebook_on_access_token_error)
39
+ controller.helper(RestCore::Facebook::RailsUtil::Helper)
40
+ controller.instance_methods.select{ |method|
41
+ method.to_s =~ /^rc_facebook/
42
+ }.each{ |method| controller.send(:protected, method) }
43
+ end
44
+
45
+ def rc_facebook_setup options={}
46
+ rc_facebook_options_ctl.merge!(
47
+ RestCore::RailsUtilUtil.extract_options(
48
+ RestCore::Facebook.members, options, :reject))
49
+ rc_facebook_options_new.merge!(
50
+ RestCore::RailsUtilUtil.extract_options(
51
+ RestCore::Facebook.members, options, :select))
52
+
53
+ # we'll need to reinitialize rc_facebook with the new options,
54
+ # otherwise if you're calling rc_facebook before rc_facebook_setup,
55
+ # you'll end up with default options without the ones you've passed
56
+ # into rc_facebook_setup.
57
+ rc_facebook.send(:initialize, rc_facebook_options_new)
58
+
59
+ rc_facebook_check_params_signed_request # canvas
60
+ rc_facebook_check_params_session # i think it would be deprecated
61
+ rc_facebook_check_cookie # for js sdk (canvas or not)
62
+ rc_facebook_check_code # oauth api
63
+
64
+ # there are above 4 ways to check the user identity!
65
+ # if nor of them passed, then we can suppose the user
66
+ # didn't authorize for us, but we can check if user has authorized
67
+ # before, in that case, the fbs would be inside session,
68
+ # as we just saved it there
69
+
70
+ rc_facebook_check_rg_fbs # check rc_facebook storage
71
+
72
+ if rc_facebook_oget(:ensure_authorized) && !rc_facebook.authorized?
73
+ rc_facebook_authorize('ensure authorized')
74
+ false # action halt, redirect to do authorize,
75
+ # eagerly, as opposed to auto_authorize
76
+ else
77
+ true # keep going
78
+ end
79
+ end
80
+
81
+ # override this if you need different app_id and secret
82
+ def rc_facebook
83
+ @rc_facebook ||= RestCore::Facebook.new(rc_facebook_options_new)
84
+ end
85
+
86
+ def rc_facebook_on_access_token_error error=nil
87
+ rc_facebook_authorize(error, false)
88
+ end
89
+
90
+ def rc_facebook_authorize error=nil, force_redirect=true
91
+ logger.warn("WARN: Facebook: #{error.inspect}")
92
+
93
+ if force_redirect || rc_facebook_auto_authorize?
94
+ @rc_facebook_authorize_url = rc_facebook.authorize_url(
95
+ {:redirect_uri => rc_facebook_normalized_request_uri,
96
+ :scope => rc_facebook_oget(:auto_authorize_scope)}.
97
+ merge(rc_facebook_oget(:auto_authorize_options)))
98
+
99
+ logger.debug(
100
+ "DEBUG: Facebook: redirect to #{@rc_facebook_authorize_url}")
101
+
102
+ cookies.delete("fbs_#{rc_facebook.app_id}")
103
+ rc_facebook_authorize_redirect
104
+ end
105
+ end
106
+
107
+ # override this if you want the simple redirect_to
108
+ def rc_facebook_authorize_redirect
109
+ unless rc_facebook_in_canvas?
110
+ redirect_to @rc_facebook_authorize_url
111
+ else
112
+ rc_facebook_js_redirect(@rc_facebook_authorize_url,
113
+ rc_facebook_authorize_body)
114
+ end
115
+ end
116
+
117
+ def rc_facebook_js_redirect redirect_url, body=''
118
+ render :inline => <<-HTML
119
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
120
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
121
+ <html>
122
+ <head>
123
+ <script type="text/javascript">
124
+ window.top.location.href = '#{redirect_url}'
125
+ </script>
126
+ <noscript>
127
+ <meta http-equiv="refresh" content="0;url=#{
128
+ CGI.escapeHTML(redirect_url)}"/>
129
+ <meta http-equiv="window-target" content="_top"/>
130
+ </noscript>
131
+ </head>
132
+ <body>
133
+ #{body}
134
+ </bodt>
135
+ </html>
136
+ HTML
137
+ end
138
+
139
+ def rc_facebook_authorize_body redirect_url=@rc_facebook_authorize_url
140
+ <<-HTML
141
+ <div>
142
+ Please
143
+ <a href="#{CGI.escapeHTML(redirect_url)}" target="_top">authorize</a>
144
+ if this page is not automatically redirected.
145
+ </div>
146
+ HTML
147
+ end
148
+
149
+ module_function
150
+
151
+ # ==================== begin options utility =======================
152
+ def rc_facebook_oget key
153
+ if rc_facebook_options_ctl.has_key?(key)
154
+ rc_facebook_options_ctl[key]
155
+ else
156
+ RestCore::Facebook.send("default_#{key}")
157
+ end
158
+ end
159
+
160
+ def rc_facebook_options_ctl
161
+ @rc_facebook_options_ctl ||= {}
162
+ end
163
+
164
+ def rc_facebook_options_new
165
+ @rc_facebook_options_new ||= {}
166
+ end
167
+ # ==================== end options utility =======================
168
+
169
+
170
+
171
+ # ==================== begin facebook check ======================
172
+ def rc_facebook_check_params_signed_request
173
+ return if rc_facebook.authorized? || !params[:signed_request]
174
+
175
+ rc_facebook.parse_signed_request!(params[:signed_request])
176
+ logger.debug("DEBUG: Facebook: detected signed_request," \
177
+ " parsed: #{rc_facebook.data.inspect}")
178
+
179
+ if rc_facebook.authorized?
180
+ rc_facebook_write_rg_fbs
181
+ else
182
+ logger.warn(
183
+ "WARN: Facebook: bad signed_request: #{params[:signed_request]}")
184
+ end
185
+ end
186
+
187
+ # if the code is bad or not existed,
188
+ # check if there's one in session,
189
+ # meanwhile, there the sig and access_token is correct,
190
+ # that means we're in the context of canvas
191
+ def rc_facebook_check_params_session
192
+ return if rc_facebook.authorized? || !params[:session]
193
+
194
+ rc_facebook.parse_json!(params[:session])
195
+ logger.debug("DEBUG: Facebook: detected session, parsed:" \
196
+ " #{rc_facebook.data.inspect}")
197
+
198
+ if rc_facebook.authorized?
199
+ rc_facebook_write_rg_fbs
200
+ else
201
+ logger.warn("WARN: Facebook: bad session: #{params[:session]}")
202
+ end
203
+ end
204
+
205
+ # if we're not in canvas nor code passed,
206
+ # we could check out cookies as well.
207
+ def rc_facebook_check_cookie
208
+ return if rc_facebook.authorized? ||
209
+ (!cookies["fbsr_#{rc_facebook.app_id}"] &&
210
+ !cookies["fbs_#{rc_facebook.app_id}"])
211
+
212
+ rc_facebook.parse_cookies!(cookies)
213
+ logger.debug("DEBUG: Facebook: detected cookies, parsed:" \
214
+ " #{rc_facebook.data.inspect}")
215
+ end
216
+
217
+ # exchange the code with access_token
218
+ def rc_facebook_check_code
219
+ return if rc_facebook.authorized? || !params[:code]
220
+
221
+ rc_facebook.authorize!(
222
+ :code => params[:code],
223
+ :redirect_uri => rc_facebook_normalized_request_uri)
224
+
225
+ logger.debug(
226
+ "DEBUG: Facebook: detected code with " \
227
+ "#{rc_facebook_normalized_request_uri}," \
228
+ " parsed: #{rc_facebook.data.inspect}")
229
+
230
+ rc_facebook_write_rg_fbs if rc_facebook.authorized?
231
+ end
232
+ # ==================== end facebook check ======================
233
+
234
+
235
+
236
+ # ==================== begin check ================================
237
+ def rc_facebook_storage_key
238
+ "rc_facebook_fbs_#{rc_facebook_oget(:app_id)}"
239
+ end
240
+
241
+ def rc_facebook_check_rg_fbs
242
+ rc_facebook_check_rg_handler # custom method to store fbs
243
+ rc_facebook_check_rg_session # prefered way to store fbs
244
+ rc_facebook_check_rg_cookies # in canvas, session might not work..
245
+ end
246
+
247
+ def rc_facebook_check_rg_handler handler=rc_facebook_oget(:check_handler)
248
+ return if rc_facebook.authorized? || !handler
249
+ rc_facebook.parse_fbs!(handler.call)
250
+ logger.debug("DEBUG: Facebook: called check_handler, parsed:" \
251
+ " #{rc_facebook.data.inspect}")
252
+ end
253
+
254
+ def rc_facebook_check_rg_session
255
+ return if rc_facebook.authorized? || !rc_facebook_oget(:write_session) ||
256
+ !(fbs = session[rc_facebook_storage_key])
257
+ rc_facebook.parse_fbs!(fbs)
258
+ logger.debug("DEBUG: Facebook: detected rc_facebook session, parsed:" \
259
+ " #{rc_facebook.data.inspect}")
260
+ end
261
+
262
+ def rc_facebook_check_rg_cookies
263
+ return if rc_facebook.authorized? || !rc_facebook_oget(:write_cookies) ||
264
+ !(fbs = cookies[rc_facebook_storage_key])
265
+ rc_facebook.parse_fbs!(fbs)
266
+ logger.debug("DEBUG: Facebook: detected rc_facebook cookies, parsed:" \
267
+ " #{rc_facebook.data.inspect}")
268
+ end
269
+ # ==================== end check ================================
270
+ # ==================== begin write ================================
271
+ def rc_facebook_write_rg_fbs
272
+ cookies.delete("fbs_#{rc_facebook.app_id}")
273
+ rc_facebook_write_rg_handler
274
+ rc_facebook_write_rg_session
275
+ rc_facebook_write_rg_cookies
276
+ end
277
+
278
+ def rc_facebook_write_rg_handler handler=rc_facebook_oget(:write_handler)
279
+ return if !handler
280
+ handler.call(fbs = rc_facebook.fbs)
281
+ logger.debug("DEBUG: Facebook: called write_handler: fbs => #{fbs}")
282
+ end
283
+
284
+ def rc_facebook_write_rg_session
285
+ return if !rc_facebook_oget(:write_session)
286
+ session[rc_facebook_storage_key] = fbs = rc_facebook.fbs
287
+ logger.debug("DEBUG: Facebook: wrote session: fbs => #{fbs}")
288
+ end
289
+
290
+ def rc_facebook_write_rg_cookies
291
+ return if !rc_facebook_oget(:write_cookies)
292
+ cookies[rc_facebook_storage_key] = fbs = rc_facebook.fbs
293
+ logger.debug("DEBUG: Facebook: wrote cookies: fbs => #{fbs}")
294
+ end
295
+ # ==================== end write ================================
296
+
297
+
298
+
299
+ # ==================== begin misc ================================
300
+ def rc_facebook_normalized_request_uri
301
+ uri = if rc_facebook_in_canvas?
302
+ # rails 3 uses newer rack which has fullpath
303
+ "http://apps.facebook.com/#{rc_facebook_oget(:canvas)}" +
304
+ (request.respond_to?(:fullpath) ?
305
+ request.fullpath : request.request_uri)
306
+ else
307
+ request.url
308
+ end
309
+
310
+ rc_facebook_filter_uri(uri)
311
+ end
312
+
313
+ def rc_facebook_filter_uri uri
314
+ URI.parse(URI.encode(uri)).tap{ |uri|
315
+ uri.query = uri.query.split('&').reject{ |q|
316
+ q =~ /^(code|session|signed_request)\=/
317
+ }.join('&') if uri.query
318
+ uri.query = nil if uri.query.blank?
319
+ }.to_s
320
+ end
321
+
322
+ def rc_facebook_in_canvas?
323
+ !rc_facebook_oget(:canvas).blank?
324
+ end
325
+
326
+ def rc_facebook_auto_authorize?
327
+ !rc_facebook_oget(:auto_authorize_scope) .blank? ||
328
+ !rc_facebook_oget(:auto_authorize_options).blank? ||
329
+ rc_facebook_oget(:auto_authorize)
330
+ end
331
+ # ==================== end misc ================================
332
+ end
333
+
334
+ RestCore::Facebook::RailsUtil.init(Rails)