canvas-lms/lib/facebook.rb

136 lines
5.0 KiB
Ruby

#
# Copyright (C) 2011-2013 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
module Facebook
API_URL = 'https://api.facebook.com'
GRAPH_URL = 'https://graph.facebook.com'
def self.parse_signed_request(signed_request)
sig, str = signed_request.split('.')
generated_sig = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha256'), config['secret'], str)).strip.tr('+/', '-_').sub(/=+$/, '')
str += '=' * (4 - str.length.modulo(4))
data = JSON.parse(str.tr('-_','+/').unpack('m')[0]) rescue nil
[data, sig == generated_sig ? sig : nil]
end
def self.dashboard_increment_count(service)
path = "#{service.service_user_id}/apprequests"
msg = I18n.t(:new_facebook_message, 'You have a new message from Canvas')
send_graph_request(path, :post, service, message: msg)
end
def self.protocol
"http#{config['disable_ssl'] ? '' : 's'}"
end
def self.authorize_url(oauth_request)
callback_url = "#{protocol}://#{config['canvas_domain']}/facebook_success.html"
state = Canvas::Security.encrypt_password(oauth_request.global_id.to_s, 'facebook_oauth_request').join('.')
"https://www.facebook.com/dialog/oauth?client_id=#{config['app_id']}&redirect_uri=#{CGI.escape(callback_url)}&response_type=token&scope=offline_access&state=#{CGI.escape(state)}"
end
def self.oauth_request_id(state)
key,salt = state.split('.', 2)
request_id = Canvas::Security.decrypt_password(key, salt, 'facebook_oauth_request')
end
def self.authorize_success(user, token)
@service = UserService.find_by_user_id_and_service(user.id, 'facebook')
@service ||= UserService.new(:user => user, :service => 'facebook')
@service.token = token
data = send_graph_request('/me', :get, @service)
return nil unless data
@service.service_user_id = data['id']
@service.service_user_name = data['name']
@service.service_user_url = data['link']
@service.save
@service
end
def self.app_url
"http://apps.facebook.com/#{ URI.escape(self.config['canvas_name']) }"
end
def self.config_check(settings)
url = "https://graph.facebook.com/oauth/access_token?client_id=#{settings['app_id']}&redirect_uri=http#{settings['disable_ssl'] ? '' : 's'}://#{settings['canvas_domain']}&client_secret=#{settings['secret']}&code=wrong&format=json"
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
tmp_url = uri.path+"?"+uri.query
request = Net::HTTP::Get.new(tmp_url)
response = http.request(request)
res = JSON.parse(response.body)
if res['error']
if res['error']['message'] == "Error validating client secret."
"Invalid app id or app secret"
elsif res['error']['message'] == "Invalid redirect_uri: Given URL is not allowed by the Application configuration."
"Invalid app id or redirect uri"
elsif res['error']['message'] == "Invalid verification code format."
# This means everything else checked out
nil
else
"Unexpected error"
end
else
# We expect to get an error in this API call, so no error means
# something bad happened
"Unexpected response from settings check"
end
end
def self.send_graph_request(path, method, service, params = {})
params[:access_token] = service.token
query_string = ActionController::Routing::Route.new.build_query_string(params)
uri = URI("#{GRAPH_URL}/#{path}#{query_string}")
client = Net::HTTP.new(uri.host, uri.port)
client.use_ssl = true
response = if method == :get
client.get(uri.request_uri)
else
client.post(uri.request_uri, '')
end
body = JSON.parse(response.body)
if body['error']
Rails.logger.error(body['error']['message'])
nil
else
body
end
end
def self.send_request(method, service, params)
params[:format] = 'json'
params[:access_token] = service.token if service
url = "#{API_URL}/method/#{method}" + ActionController::Routing::Route.new.build_query_string(params)
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
tmp_url = uri.path+"?"+uri.query
request = Net::HTTP::Get.new(tmp_url)
response = http.request(request)
response.body
end
def self.config
res = Canvas::Plugin.find(:facebook).try(:settings)
res && res['app_id'] ? res : nil
end
end