require 'rest-core/util/rails_util_util'
require 'cgi'
require 'uri'
module RestCore::Facebook::DefaultAttributes
def default_log_method ; Rails.logger.method(:debug); end
def default_cache ; Rails.cache ; end
def default_canvas ; '' ; end
def default_iframe ; false ; end
def default_auto_authorize ; false ; end
def default_auto_authorize_options; {} ; end
def default_auto_authorize_scope ; '' ; end
def default_ensure_authorized ; false ; end
def default_write_session ; false ; end
def default_write_cookies ; false ; end
def default_write_handler ; nil ; end
def default_check_handler ; nil ; end
end
module RestCore::Facebook::RailsUtil
include RestCore::RailsUtilUtil
def self.included controller
# skip if included already, any better way to detect this?
return if controller.respond_to?(:rc_facebook, true)
super
controller.rescue_from(RestCore::Facebook::Error::AccessToken,
:with => :rc_facebook_on_access_token_error)
end
def rc_facebook_setup options={}
super
rc_facebook_check_params_signed_request # canvas
rc_facebook_check_params_session # i think it would be deprecated
rc_facebook_check_cookie # for js sdk (canvas or not)
rc_facebook_check_code # oauth api
# there are above 4 ways to check the user identity!
# if nor of them passed, then we can suppose the user
# didn't authorize for us, but we can check if user has authorized
# before, in that case, the fbs would be inside session,
# as we just saved it there
rc_facebook_check_fbs # check rc_facebook storage
if rc_options_get(RestCore::Facebook, :ensure_authorized) &&
!rc_facebook.authorized?
rc_facebook_authorize('ensure authorized')
false # action halt, redirect to do authorize,
# eagerly, as opposed to auto_authorize
else
true # keep going
end
end
def rc_facebook_on_access_token_error error=nil
rc_facebook_authorize(error, false)
end
def rc_facebook_authorize error=nil, force_redirect=true
logger.warn("WARN: Facebook: #{error.inspect}")
if force_redirect || rc_facebook_auto_authorize?
rc_facebook_cleanup
@rc_facebook_authorize_url = rc_facebook.authorize_url(
{:redirect_uri => rc_facebook_normalized_request_uri,
:scope =>
rc_options_get(RestCore::Facebook, :auto_authorize_scope)}.
merge(rc_options_get(RestCore::Facebook, :auto_authorize_options)))
logger.debug(
"DEBUG: Facebook: redirect to #{@rc_facebook_authorize_url}")
rc_facebook_authorize_redirect
end
end
# override this if you want the simple redirect_to
def rc_facebook_authorize_redirect
unless rc_facebook_in_canvas?
redirect_to @rc_facebook_authorize_url
else
rc_facebook_js_redirect(@rc_facebook_authorize_url,
rc_facebook_authorize_body)
end
end
def rc_facebook_js_redirect redirect_url, body=''
render :inline => <<-HTML
#{body}
HTML
end
def rc_facebook_authorize_body redirect_url=@rc_facebook_authorize_url
<<-HTML
Please
authorize
if this page is not automatically redirected.
HTML
end
# ==================== begin facebook check ======================
def rc_facebook_check_params_signed_request
return if rc_facebook.authorized? || !params[:signed_request]
rc_facebook.parse_signed_request!(params[:signed_request])
logger.debug("DEBUG: Facebook: detected signed_request," \
" parsed: #{rc_facebook.data.inspect}")
if rc_facebook.authorized?
rc_facebook_write_fbs
else
logger.warn(
"WARN: Facebook: bad signed_request: #{params[:signed_request]}")
end
end
# if the code is bad or not existed,
# check if there's one in session,
# meanwhile, there the sig and access_token is correct,
# that means we're in the context of canvas
def rc_facebook_check_params_session
return if rc_facebook.authorized? || !params[:session]
rc_facebook.parse_json!(params[:session])
logger.debug("DEBUG: Facebook: detected session, parsed:" \
" #{rc_facebook.data.inspect}")
if rc_facebook.authorized?
rc_facebook_write_fbs
else
logger.warn("WARN: Facebook: bad session: #{params[:session]}")
end
end
# if we're not in canvas nor code passed,
# we could check out cookies as well.
def rc_facebook_check_cookie
return if rc_facebook.authorized? ||
(!cookies["fbsr_#{rc_facebook.app_id}"] &&
!cookies["fbs_#{rc_facebook.app_id}"])
rc_facebook.parse_cookies!(cookies)
logger.debug("DEBUG: Facebook: detected cookies, parsed:" \
" #{rc_facebook.data.inspect}")
end
# exchange the code with access_token
def rc_facebook_check_code
return if rc_facebook.authorized? || !params[:code]
rc_facebook.authorize!(
:code => params[:code],
:redirect_uri => rc_facebook_normalized_request_uri)
logger.debug(
"DEBUG: Facebook: detected code with " \
"#{rc_facebook_normalized_request_uri}," \
" parsed: #{rc_facebook.data.inspect}")
rc_facebook_write_fbs if rc_facebook.authorized?
end
# ==================== end facebook check ======================
# ==================== begin check ================================
def rc_facebook_storage_key
"rc_facebook_#{rc_facebook.app_id}"
end
def rc_facebook_check_fbs
rc_facebook_check_handler # custom method to store fbs
rc_facebook_check_session # prefered way to store fbs
rc_facebook_check_cookies # in canvas, session might not work..
end
def rc_facebook_check_handler handler=
rc_options_get(RestCore::Facebook, :check_handler)
return if rc_facebook.authorized? || !handler
rc_facebook.parse_fbs!(handler.call)
logger.debug("DEBUG: Facebook: called check_handler, parsed:" \
" #{rc_facebook.data.inspect}")
end
def rc_facebook_check_session
return if rc_facebook.authorized? ||
!rc_options_get(RestCore::Facebook, :write_session) ||
!(fbs = session[rc_facebook_storage_key])
rc_facebook.parse_fbs!(fbs)
logger.debug("DEBUG: Facebook: detected rc_facebook session, parsed:" \
" #{rc_facebook.data.inspect}")
end
def rc_facebook_check_cookies
return if rc_facebook.authorized? ||
!rc_options_get(RestCore::Facebook, :write_cookies) ||
!(fbs = cookies[rc_facebook_storage_key])
rc_facebook.parse_fbs!(fbs)
logger.debug("DEBUG: Facebook: detected rc_facebook cookies, parsed:" \
" #{rc_facebook.data.inspect}")
end
# ==================== end check ================================
# ==================== begin write ================================
def rc_facebook_write_fbs
rc_facebook_write_handler
rc_facebook_write_session
rc_facebook_write_cookies
end
def rc_facebook_write_handler handler=
rc_options_get(RestCore::Facebook, :write_handler)
return if !handler
handler.call(fbs = rc_facebook.fbs)
logger.debug("DEBUG: Facebook: called write_handler: fbs => #{fbs}")
end
def rc_facebook_write_session
return if !rc_options_get(RestCore::Facebook, :write_session)
session[rc_facebook_storage_key] = fbs = rc_facebook.fbs
logger.debug("DEBUG: Facebook: wrote session: fbs => #{fbs}")
end
def rc_facebook_write_cookies
return if !rc_options_get(RestCore::Facebook, :write_cookies)
cookies[rc_facebook_storage_key] = fbs = rc_facebook.fbs
logger.debug("DEBUG: Facebook: wrote cookies: fbs => #{fbs}")
end
# ==================== end write ================================
# ==================== begin misc ================================
def rc_facebook_cleanup
cookies.delete("fbs_#{rc_facebook.app_id}")
cookies.delete("fbsr_#{rc_facebook.app_id}")
cookies.delete(rc_facebook_storage_key)
session.delete(rc_facebook_storage_key)
end
def rc_facebook_normalized_request_uri
uri = if rc_facebook_in_canvas?
# rails 3 uses newer rack which has fullpath
"http://apps.facebook.com/#{
rc_options_get(RestCore::Facebook, :canvas)}" +
(request.respond_to?(:fullpath) ?
request.fullpath : request.request_uri)
else
request.url
end
rc_facebook_filter_uri(uri)
end
def rc_facebook_filter_uri uri
URI.parse(URI.encode(uri)).tap{ |uri|
uri.query = uri.query.split('&').reject{ |q|
q =~ /^(code|session|signed_request)\=/
}.join('&') if uri.query
uri.query = nil if uri.query.blank?
}.to_s
end
def rc_facebook_in_canvas?
!rc_options_get(RestCore::Facebook, :canvas).blank?
end
def rc_facebook_auto_authorize?
client = RestCore::Facebook
!rc_options_get(client, :auto_authorize_scope) .blank? ||
!rc_options_get(client, :auto_authorize_options).blank? ||
rc_options_get(client, :auto_authorize)
end
# ==================== end misc ================================
end
RestCore::Facebook::RailsUtil.init(Rails)