cotweet_koala 0.8.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +88 -0
- data/LICENSE +22 -0
- data/Manifest +29 -0
- data/Rakefile +16 -0
- data/init.rb +2 -0
- data/koala.gemspec +30 -0
- data/lib/koala.rb +292 -0
- data/lib/koala/graph_api.rb +136 -0
- data/lib/koala/http_services.rb +85 -0
- data/lib/koala/realtime_updates.rb +95 -0
- data/lib/koala/rest_api.rb +23 -0
- data/readme.md +104 -0
- data/spec/facebook_data.yml +44 -0
- data/spec/koala/api_base_tests.rb +80 -0
- data/spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb +10 -0
- data/spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb +11 -0
- data/spec/koala/graph_api/graph_api_no_access_token_tests.rb +105 -0
- data/spec/koala/graph_api/graph_api_with_access_token_tests.rb +139 -0
- data/spec/koala/live_testing_data_helper.rb +15 -0
- data/spec/koala/net_http_service_tests.rb +181 -0
- data/spec/koala/oauth/oauth_tests.rb +308 -0
- data/spec/koala/realtime_updates/realtime_updates_tests.rb +187 -0
- data/spec/koala/rest_api/rest_api_no_access_token_tests.rb +94 -0
- data/spec/koala/rest_api/rest_api_with_access_token_tests.rb +36 -0
- data/spec/koala_spec.rb +18 -0
- data/spec/koala_spec_helper.rb +30 -0
- data/spec/koala_spec_without_mocks.rb +19 -0
- data/spec/mock_facebook_responses.yml +228 -0
- data/spec/mock_http_service.rb +81 -0
- metadata +108 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
v0.8.0
|
2
|
+
-- Breaking interface changes
|
3
|
+
-- Removed string overloading for the methods, per 0.7.3, which caused Marshaling issues
|
4
|
+
-- Removed ability to provide a string as the second argument to url_for_access_token, per 0.5.0
|
5
|
+
|
6
|
+
v0.7.4
|
7
|
+
-- Fixed bug with get_user_from_cookies
|
8
|
+
|
9
|
+
v0.7.3
|
10
|
+
-- Added support for picture sizes -- thanks thhermansen for the patch!
|
11
|
+
-- Adjusted the return values for several methods (get_access_token, get_app_access_token, get_token_from_session_key, get_tokens_from_session_keys, get_user_from_cookies)
|
12
|
+
-- These methods now return strings, rather than hashes, which makes more sense
|
13
|
+
-- The strings are overloaded with an [] method for backwards compatibility (Ruby is truly amazing)
|
14
|
+
-- Using those methods triggers a deprecation warning
|
15
|
+
-- This will be removed by 1.0
|
16
|
+
-- There are new info methods (get_access_token_info, get_app_access_token_info, get_token_info_from_session_keys, and get_user_info_from_cookies) that natively return hashes, for when you want the expiration date
|
17
|
+
-- Responses with HTTP status 500+ now properly throw errors under Net::HTTP
|
18
|
+
-- Updated changelog
|
19
|
+
-- Added license
|
20
|
+
|
21
|
+
v0.7.2
|
22
|
+
-- Added support for exchanging session keys for OAuth access tokens (get_token_from_session_key for single keys, get_tokens_from_session_keys for multiple)
|
23
|
+
-- Moved Koala files into a koala/ subdirectory to minimize risk of name collisions
|
24
|
+
-- Added OAuth Playground git submodule as an example
|
25
|
+
-- Updated tests, readme, and changelog
|
26
|
+
|
27
|
+
v0.7.1
|
28
|
+
-- Updated RealtimeUpdates#list_subscriptions and GraphAPI#get_connections to now return an
|
29
|
+
array of results directly (rather than a hash with one key)
|
30
|
+
-- Fixed a bug with Net::HTTP-based HTTP service in which the headers hash was improperly formatted
|
31
|
+
-- Updated readme
|
32
|
+
|
33
|
+
v0.7.0
|
34
|
+
-- Added RealtimeUpdates class, which can be used to manage subscriptions for user updates (see http://developers.facebook.com/docs/api/realtime)
|
35
|
+
-- Added picture method to graph API, which fetches an object's picture from the redirect headers.
|
36
|
+
-- Added _greatly_ improved testing with result mocking, which is now the default set of tests
|
37
|
+
-- Renamed live testing spec to koala_spec_without_mocks.rb
|
38
|
+
-- Added Koala::Response class, which encapsulates HTTP results since Facebook sometimes sends data in the status or headers
|
39
|
+
-- Much internal refactoring
|
40
|
+
-- Updated readme, changelog, etc.
|
41
|
+
|
42
|
+
|
43
|
+
v0.6.0
|
44
|
+
-- Added support for the old REST API thanks to cbaclig's great work
|
45
|
+
-- Updated tests to conform to RSpec standards
|
46
|
+
-- Updated changelog, readme, etc.
|
47
|
+
|
48
|
+
v0.5.1
|
49
|
+
-- Documentation is now on the wiki, updated readme accordingly.
|
50
|
+
|
51
|
+
v0.5.0
|
52
|
+
-- Added several new OAuth methods for making and parsing access token requests
|
53
|
+
-- Added test suite for the OAuth class
|
54
|
+
-- Made second argument to url_for_access_token a hash (strings still work but trigger a deprecation warning)
|
55
|
+
-- Added fields to facebook_data.yml
|
56
|
+
-- Updated readme
|
57
|
+
|
58
|
+
v0.4.1
|
59
|
+
-- Encapsulated GraphAPI and OAuth classes in the Koala::Facebook module for clarity (and to avoid claiming the global Facebook class)
|
60
|
+
-- Moved make_request method to Koala class from GraphAPI instance (for use by future OAuth class functionality)
|
61
|
+
-- Renamed request method to api for consistancy with Javascript library
|
62
|
+
-- Updated tests and readme
|
63
|
+
|
64
|
+
v0.4.0
|
65
|
+
-- Adopted the Koala name
|
66
|
+
-- Updated readme and tests
|
67
|
+
-- Fixed cookie verification bug for non-expiring OAuth tokens
|
68
|
+
|
69
|
+
v0.3.1
|
70
|
+
-- Bug fixes.
|
71
|
+
|
72
|
+
v0.3
|
73
|
+
-- Renamed Graph API class from Facebook::GraphAPI to FacebookGraph::API
|
74
|
+
-- Created FacebookGraph::OAuth class for tokens and OAuth URLs
|
75
|
+
-- Updated method for including HTTP service (think we've got it this time)
|
76
|
+
-- Updated tests
|
77
|
+
-- Added CHANGELOG and gemspec
|
78
|
+
|
79
|
+
v0.2
|
80
|
+
-- Gemified the project
|
81
|
+
-- Split out HTTP services into their own file, and adjusted inclusion method
|
82
|
+
|
83
|
+
v0.1
|
84
|
+
-- Added modular support for Typhoeus
|
85
|
+
-- Added tests
|
86
|
+
|
87
|
+
v0.0
|
88
|
+
-- Hi from F8! Basic read/write from the graph is working
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2010 Alex Koppel
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
LICENSE
|
3
|
+
Manifest
|
4
|
+
Rakefile
|
5
|
+
init.rb
|
6
|
+
koala.gemspec
|
7
|
+
lib/koala.rb
|
8
|
+
lib/koala/graph_api.rb
|
9
|
+
lib/koala/http_services.rb
|
10
|
+
lib/koala/realtime_updates.rb
|
11
|
+
lib/koala/rest_api.rb
|
12
|
+
readme.md
|
13
|
+
spec/facebook_data.yml
|
14
|
+
spec/koala/api_base_tests.rb
|
15
|
+
spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb
|
16
|
+
spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb
|
17
|
+
spec/koala/graph_api/graph_api_no_access_token_tests.rb
|
18
|
+
spec/koala/graph_api/graph_api_with_access_token_tests.rb
|
19
|
+
spec/koala/live_testing_data_helper.rb
|
20
|
+
spec/koala/net_http_service_tests.rb
|
21
|
+
spec/koala/oauth/oauth_tests.rb
|
22
|
+
spec/koala/realtime_updates/realtime_updates_tests.rb
|
23
|
+
spec/koala/rest_api/rest_api_no_access_token_tests.rb
|
24
|
+
spec/koala/rest_api/rest_api_with_access_token_tests.rb
|
25
|
+
spec/koala_spec.rb
|
26
|
+
spec/koala_spec_helper.rb
|
27
|
+
spec/koala_spec_without_mocks.rb
|
28
|
+
spec/mock_facebook_responses.yml
|
29
|
+
spec/mock_http_service.rb
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Rakefile
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake'
|
4
|
+
require 'echoe'
|
5
|
+
|
6
|
+
# gem management
|
7
|
+
Echoe.new('koala', '0.8.0') do |p|
|
8
|
+
p.summary = "A lightweight, flexible library for Facebook with support for the Graph API, the old REST API, realtime updates, and OAuth validation."
|
9
|
+
p.description = "Koala is a lightweight, flexible Ruby SDK for Facebook. It allows read/write access to the social graph via the Graph API and the older REST API, as well as support for realtime updates and OAuth and Facebook Connect authentication. Koala is fully tested and supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services."
|
10
|
+
p.url = "http://github.com/arsduo/koala"
|
11
|
+
p.author = ["Alex Koppel", "Chris Baclig", "Rafi Jacoby", "Context Optional"]
|
12
|
+
p.email = "alex@alexkoppel.com"
|
13
|
+
p.ignore_pattern = ["tmp/*", "script/*", "pkg/*"]
|
14
|
+
p.development_dependencies = []
|
15
|
+
p.retain_gemspec = true
|
16
|
+
end
|
data/init.rb
ADDED
data/koala.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{cotweet_koala}
|
5
|
+
s.version = "0.8.0.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional"]
|
9
|
+
s.date = %q{2010-06-27}
|
10
|
+
s.description = %q{Koala is a lightweight, flexible Ruby SDK for Facebook. It allows read/write access to the social graph via the Graph API and the older REST API, as well as support for realtime updates and OAuth and Facebook Connect authentication. Koala is fully tested and supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services.}
|
11
|
+
s.email = %q{alex@alexkoppel.com}
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "lib/koala.rb", "lib/koala/graph_api.rb", "lib/koala/http_services.rb", "lib/koala/realtime_updates.rb", "lib/koala/rest_api.rb"]
|
13
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "Rakefile", "init.rb", "koala.gemspec", "lib/koala.rb", "lib/koala/graph_api.rb", "lib/koala/http_services.rb", "lib/koala/realtime_updates.rb", "lib/koala/rest_api.rb", "readme.md", "spec/facebook_data.yml", "spec/koala/api_base_tests.rb", "spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb", "spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb", "spec/koala/graph_api/graph_api_no_access_token_tests.rb", "spec/koala/graph_api/graph_api_with_access_token_tests.rb", "spec/koala/live_testing_data_helper.rb", "spec/koala/net_http_service_tests.rb", "spec/koala/oauth/oauth_tests.rb", "spec/koala/realtime_updates/realtime_updates_tests.rb", "spec/koala/rest_api/rest_api_no_access_token_tests.rb", "spec/koala/rest_api/rest_api_with_access_token_tests.rb", "spec/koala_spec.rb", "spec/koala_spec_helper.rb", "spec/koala_spec_without_mocks.rb", "spec/mock_facebook_responses.yml", "spec/mock_http_service.rb"]
|
14
|
+
s.homepage = %q{http://github.com/arsduo/koala}
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Koala", "--main", "readme.md"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{koala}
|
18
|
+
s.rubygems_version = %q{1.3.6}
|
19
|
+
s.summary = %q{A lightweight, flexible library for Facebook with support for the Graph API, the old REST API, realtime updates, and OAuth validation.}
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
+
s.specification_version = 3
|
24
|
+
|
25
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
|
+
else
|
27
|
+
end
|
28
|
+
else
|
29
|
+
end
|
30
|
+
end
|
data/lib/koala.rb
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'digest/md5'
|
3
|
+
|
4
|
+
# rubygems is required to support json, how facebook returns data
|
5
|
+
require 'rubygems'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
# openssl is required to support signed_request
|
9
|
+
require 'openssl'
|
10
|
+
|
11
|
+
# include default http services
|
12
|
+
require 'koala/http_services'
|
13
|
+
|
14
|
+
# add Graph API methods
|
15
|
+
require 'koala/graph_api'
|
16
|
+
|
17
|
+
# add REST API methods
|
18
|
+
require 'koala/rest_api'
|
19
|
+
|
20
|
+
require 'koala/realtime_updates'
|
21
|
+
|
22
|
+
module Koala
|
23
|
+
|
24
|
+
module Facebook
|
25
|
+
# Ruby client library for the Facebook Platform.
|
26
|
+
# Copyright 2010 Facebook
|
27
|
+
# Adapted from the Python library by Alex Koppel, Rafi Jacoby, and the team at Context Optional
|
28
|
+
#
|
29
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
30
|
+
# not use this file except in compliance with the License. You may obtain
|
31
|
+
# a copy of the License at
|
32
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
33
|
+
#
|
34
|
+
# Unless required by applicable law or agreed to in writing, software
|
35
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
36
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
37
|
+
# License for the specific language governing permissions and limitations
|
38
|
+
# under the License.
|
39
|
+
#
|
40
|
+
# This client library is designed to support the Graph API and the official
|
41
|
+
# Facebook JavaScript SDK, which is the canonical way to implement
|
42
|
+
# Facebook authentication. Read more about the Graph API at
|
43
|
+
# http://developers.facebook.com/docs/api. You can download the Facebook
|
44
|
+
# JavaScript SDK at http://github.com/facebook/connect-js/.
|
45
|
+
|
46
|
+
class API
|
47
|
+
# initialize with an access token
|
48
|
+
def initialize(access_token = nil)
|
49
|
+
@access_token = access_token
|
50
|
+
end
|
51
|
+
|
52
|
+
def api(path, args = {}, verb = "get", options = {}, &error_checking_block)
|
53
|
+
# Fetches the given path in the Graph API.
|
54
|
+
args["access_token"] = @access_token || @app_access_token if @access_token || @app_access_token
|
55
|
+
# make the request via the provided service
|
56
|
+
result = Koala.make_request(path, args, verb, options)
|
57
|
+
|
58
|
+
# Check for any 500 errors before parsing the body
|
59
|
+
# since we're not guaranteed that the body is valid JSON
|
60
|
+
# in the case of a server error
|
61
|
+
raise APIError.new({"type" => "HTTP #{result.status.to_s}", "message" => "Response body: #{result.body}"}) if result.status >= 500
|
62
|
+
|
63
|
+
# Parse the body as JSON and check for errors if provided a mechanism to do so
|
64
|
+
# Note: Facebook sometimes sends results like "true" and "false", which aren't strictly objects
|
65
|
+
# and cause JSON.parse to fail -- so we account for that by wrapping the result in []
|
66
|
+
body = response = JSON.parse("[#{result.body.to_s}]")[0]
|
67
|
+
if error_checking_block
|
68
|
+
yield(body)
|
69
|
+
end
|
70
|
+
|
71
|
+
# now return the desired information
|
72
|
+
if options[:http_component]
|
73
|
+
result.send(options[:http_component])
|
74
|
+
else
|
75
|
+
body
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class GraphAPI < API
|
81
|
+
include GraphAPIMethods
|
82
|
+
end
|
83
|
+
|
84
|
+
class RestAPI < API
|
85
|
+
include RestAPIMethods
|
86
|
+
end
|
87
|
+
|
88
|
+
class GraphAndRestAPI < API
|
89
|
+
include GraphAPIMethods
|
90
|
+
include RestAPIMethods
|
91
|
+
end
|
92
|
+
|
93
|
+
class RealtimeUpdates < API
|
94
|
+
include RealtimeUpdateMethods
|
95
|
+
end
|
96
|
+
|
97
|
+
class APIError < Exception
|
98
|
+
attr_accessor :fb_error_type
|
99
|
+
def initialize(details = {})
|
100
|
+
self.fb_error_type = details["type"]
|
101
|
+
super("#{fb_error_type}: #{details["message"]}")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
class OAuth
|
107
|
+
attr_reader :app_id, :app_secret, :oauth_callback_url
|
108
|
+
def initialize(app_id, app_secret, oauth_callback_url = nil)
|
109
|
+
@app_id = app_id
|
110
|
+
@app_secret = app_secret
|
111
|
+
@oauth_callback_url = oauth_callback_url
|
112
|
+
end
|
113
|
+
|
114
|
+
def get_user_info_from_cookie(cookie_hash)
|
115
|
+
# Parses the cookie set by the official Facebook JavaScript SDK.
|
116
|
+
#
|
117
|
+
# cookies should be a Hash, like the one Rails provides
|
118
|
+
#
|
119
|
+
# If the user is logged in via Facebook, we return a dictionary with the
|
120
|
+
# keys "uid" and "access_token". The former is the user's Facebook ID,
|
121
|
+
# and the latter can be used to make authenticated requests to the Graph API.
|
122
|
+
# If the user is not logged in, we return None.
|
123
|
+
#
|
124
|
+
# Download the official Facebook JavaScript SDK at
|
125
|
+
# http://github.com/facebook/connect-js/. Read more about Facebook
|
126
|
+
# authentication at http://developers.facebook.com/docs/authentication/.
|
127
|
+
|
128
|
+
if fb_cookie = cookie_hash["fbs_" + @app_id.to_s]
|
129
|
+
# remove the opening/closing quote
|
130
|
+
fb_cookie = fb_cookie.gsub(/\"/, "")
|
131
|
+
|
132
|
+
# since we no longer get individual cookies, we have to separate out the components ourselves
|
133
|
+
components = {}
|
134
|
+
fb_cookie.split("&").map {|param| param = param.split("="); components[param[0]] = param[1]}
|
135
|
+
|
136
|
+
# generate the signature and make sure it matches what we expect
|
137
|
+
auth_string = components.keys.sort.collect {|a| a == "sig" ? nil : "#{a}=#{components[a]}"}.reject {|a| a.nil?}.join("")
|
138
|
+
sig = Digest::MD5.hexdigest(auth_string + @app_secret)
|
139
|
+
sig == components["sig"] && (components["expires"] == "0" || Time.now.to_i < components["expires"].to_i) ? components : nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
alias_method :get_user_info_from_cookies, :get_user_info_from_cookie
|
143
|
+
|
144
|
+
def get_user_from_cookie(cookies)
|
145
|
+
if info = get_user_info_from_cookies(cookies)
|
146
|
+
string = info["uid"]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
alias_method :get_user_from_cookies, :get_user_from_cookie
|
150
|
+
|
151
|
+
# URLs
|
152
|
+
|
153
|
+
def url_for_oauth_code(options = {})
|
154
|
+
# for permissions, see http://developers.facebook.com/docs/authentication/permissions
|
155
|
+
permissions = options[:permissions]
|
156
|
+
scope = permissions ? "&scope=#{permissions.is_a?(Array) ? permissions.join(",") : permissions}" : ""
|
157
|
+
|
158
|
+
callback = options[:callback] || @oauth_callback_url
|
159
|
+
raise ArgumentError, "url_for_oauth_code must get a callback either from the OAuth object or in the options!" unless callback
|
160
|
+
|
161
|
+
# Creates the URL for oauth authorization for a given callback and optional set of permissions
|
162
|
+
"https://#{GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{callback}#{scope}"
|
163
|
+
end
|
164
|
+
|
165
|
+
def url_for_access_token(code, options = {})
|
166
|
+
# Creates the URL for the token corresponding to a given code generated by Facebook
|
167
|
+
callback = options[:callback] || @oauth_callback_url
|
168
|
+
raise ArgumentError, "url_for_access_token must get a callback either from the OAuth object or in the parameters!" unless callback
|
169
|
+
"https://#{GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&redirect_uri=#{callback}&client_secret=#{@app_secret}&code=#{code}"
|
170
|
+
end
|
171
|
+
|
172
|
+
def get_access_token_info(code)
|
173
|
+
# convenience method to get a parsed token from Facebook for a given code
|
174
|
+
# should this require an OAuth callback URL?
|
175
|
+
get_token_from_server(:code => code, :redirect_uri => @oauth_callback_url)
|
176
|
+
end
|
177
|
+
|
178
|
+
def get_access_token(code)
|
179
|
+
# upstream methods will throw errors if needed
|
180
|
+
if info = get_access_token_info(code)
|
181
|
+
string = info["access_token"]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def get_app_access_token_info
|
186
|
+
# convenience method to get a the application's sessionless access token
|
187
|
+
get_token_from_server({:type => 'client_cred'}, true)
|
188
|
+
end
|
189
|
+
|
190
|
+
def get_app_access_token
|
191
|
+
if info = get_app_access_token_info
|
192
|
+
string = info["access_token"]
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# signed_request
|
197
|
+
def parse_signed_request(request)
|
198
|
+
# Facebook's signed requests come in two parts -- the signature and the data payload
|
199
|
+
encoded_sig, payload = request.split(".")
|
200
|
+
|
201
|
+
sig = base64_url_decode(encoded_sig)
|
202
|
+
|
203
|
+
# if the signature matches, return the data, decoded and parsed as JSON
|
204
|
+
if OpenSSL::HMAC.digest("sha256", @app_secret, payload) == sig
|
205
|
+
JSON.parse(base64_url_decode(payload))
|
206
|
+
else
|
207
|
+
nil
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# from session keys
|
212
|
+
def get_token_info_from_session_keys(sessions)
|
213
|
+
# fetch the OAuth tokens from Facebook
|
214
|
+
response = fetch_token_string({
|
215
|
+
:type => 'client_cred',
|
216
|
+
:sessions => sessions.join(",")
|
217
|
+
}, true, "exchange_sessions")
|
218
|
+
|
219
|
+
# get_token_from_session_key should return an empty body if an empty string or nil is provided
|
220
|
+
# if invalid tokens are provided, it returns an array of nulls, which is a valid result
|
221
|
+
if response == ""
|
222
|
+
raise APIError.new("ArgumentError", "get_token_from_session_key received an error (empty response body) for sessions #{sessions.inspect}!")
|
223
|
+
end
|
224
|
+
|
225
|
+
JSON.parse(response)
|
226
|
+
end
|
227
|
+
|
228
|
+
def get_tokens_from_session_keys(sessions)
|
229
|
+
# get the original hash results
|
230
|
+
results = get_token_info_from_session_keys(sessions)
|
231
|
+
# now recollect them as just the access tokens
|
232
|
+
results.collect { |r| string = r["access_token"] }
|
233
|
+
end
|
234
|
+
|
235
|
+
def get_token_from_session_key(session)
|
236
|
+
# convenience method for a single key
|
237
|
+
# gets the overlaoded strings automatically
|
238
|
+
get_tokens_from_session_keys([session])[0]
|
239
|
+
end
|
240
|
+
|
241
|
+
protected
|
242
|
+
|
243
|
+
def get_token_from_server(args, post = false)
|
244
|
+
# fetch the result from Facebook's servers
|
245
|
+
result = fetch_token_string(args, post)
|
246
|
+
|
247
|
+
# if we have an error, parse the error JSON and raise an error
|
248
|
+
raise APIError.new((JSON.parse(result)["error"] rescue nil) || {}) if result =~ /error/
|
249
|
+
|
250
|
+
# otherwise, parse the access token
|
251
|
+
parse_access_token(result)
|
252
|
+
end
|
253
|
+
|
254
|
+
def parse_access_token(response_text)
|
255
|
+
components = response_text.split("&").inject({}) do |hash, bit|
|
256
|
+
key, value = bit.split("=")
|
257
|
+
hash.merge!(key => value)
|
258
|
+
end
|
259
|
+
components
|
260
|
+
end
|
261
|
+
|
262
|
+
def fetch_token_string(args, post = false, endpoint = "access_token")
|
263
|
+
Koala.make_request("oauth/#{endpoint}", {
|
264
|
+
:client_id => @app_id,
|
265
|
+
:client_secret => @app_secret
|
266
|
+
}.merge!(args), post ? "post" : "get").body
|
267
|
+
end
|
268
|
+
|
269
|
+
# base 64
|
270
|
+
def base64_url_decode(string)
|
271
|
+
# to properly decode what Facebook provides, we need to add == to the end
|
272
|
+
# and translate certain characters to others before running the actual decoding
|
273
|
+
# see http://developers.facebook.com/docs/authentication/canvas
|
274
|
+
"#{string}==".tr("-_", "+/").unpack("m")[0]
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# finally, set up the http service Koala methods used to make requests
|
280
|
+
# you can use your own (for HTTParty, etc.) by calling Koala.http_service = YourModule
|
281
|
+
def self.http_service=(service)
|
282
|
+
self.send(:include, service)
|
283
|
+
end
|
284
|
+
|
285
|
+
# by default, try requiring Typhoeus -- if that works, use it
|
286
|
+
# begin
|
287
|
+
# require 'typhoeus'
|
288
|
+
# Koala.http_service = TyphoeusService
|
289
|
+
# rescue LoadError
|
290
|
+
Koala.http_service = NetHTTPService
|
291
|
+
# end
|
292
|
+
end
|