buddy 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +26 -0
- data/lib/buddy/rails/backwards_compatible_param_checks.rb +33 -0
- data/lib/buddy/rails/controller.rb +88 -0
- data/lib/buddy/rails/controller_extensions.rb +31 -0
- data/lib/buddy/rails/url_helper.rb +24 -0
- data/lib/buddy/railtie.rb +19 -0
- data/lib/buddy/service.rb +54 -0
- data/lib/buddy/session.rb +91 -0
- data/lib/buddy/user.rb +22 -0
- data/lib/buddy.rb +70 -0
- data/lib/rack/facebook.rb +86 -0
- data/test/test_buddy.rb +10 -0
- metadata +115 -0
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Buddy
|
2
|
+
|
3
|
+
Buddy is a lightweight Facebook library for Ruby.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
* Support for iFrame Apps
|
8
|
+
* Uses signed_request parameters for authentication
|
9
|
+
* Supports the Graph API and old REST API
|
10
|
+
* Fully compatible with **Rails 3** and **Ruby 1.9.2**
|
11
|
+
|
12
|
+
|
13
|
+
## License
|
14
|
+
|
15
|
+
released under the **MIT license**
|
16
|
+
|
17
|
+
Copyright (c) 2010:
|
18
|
+
|
19
|
+
* Ole Riesenberg
|
20
|
+
* Klaus Breyer
|
21
|
+
|
22
|
+
Some concepts and code adapted from [Facebooker](http://github.com/mmangino/facebooker)
|
23
|
+
|
24
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
25
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
26
|
+
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Buddy
|
2
|
+
module Rails
|
3
|
+
module BackwardsCompatibleParamChecks
|
4
|
+
def one_or_true( value )
|
5
|
+
case value
|
6
|
+
when String then
|
7
|
+
value == "1"
|
8
|
+
when Numeric then
|
9
|
+
value.to_f == 1.0
|
10
|
+
when TrueClass then
|
11
|
+
true
|
12
|
+
else
|
13
|
+
false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def zero_or_false( value )
|
18
|
+
case value
|
19
|
+
when String then
|
20
|
+
value.empty? || value == "0"
|
21
|
+
when Numeric then
|
22
|
+
value.to_f == 0.0
|
23
|
+
when FalseClass then
|
24
|
+
true
|
25
|
+
when NilClass then
|
26
|
+
true
|
27
|
+
else
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Buddy
|
2
|
+
module Rails
|
3
|
+
module Controller
|
4
|
+
include Buddy::Rails::BackwardsCompatibleParamChecks
|
5
|
+
include Buddy::Rails::UrlHelper
|
6
|
+
|
7
|
+
def self.included(controller)
|
8
|
+
controller.helper_method :request_comes_from_facebook?
|
9
|
+
end
|
10
|
+
|
11
|
+
def js_redirect_to(uri, target = nil)
|
12
|
+
if request_is_facebook_canvas? and !request_is_facebook_tab? and !target.nil?
|
13
|
+
render(:text => "<script>#{target.to_s}.location.href='#{uri}'</script>", :layout => false)
|
14
|
+
elsif request_is_facebook_canvas? and !request_is_facebook_tab?
|
15
|
+
render(:text => "<script>self.location.href='#{uri}'</script>", :layout => false)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def top_redirect_to(uri)
|
20
|
+
js_redirect_to(uri, :top)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def facebook_session
|
25
|
+
@facebook_session
|
26
|
+
end
|
27
|
+
|
28
|
+
def application_is_installed?
|
29
|
+
!params[:oauth_token].blank?
|
30
|
+
end
|
31
|
+
|
32
|
+
def request_is_facebook_canvas?
|
33
|
+
params[:profile_id].blank?
|
34
|
+
end
|
35
|
+
|
36
|
+
def request_is_facebook_tab?
|
37
|
+
!params[:profile_id].blank?
|
38
|
+
end
|
39
|
+
|
40
|
+
def clear_facebook_session_information
|
41
|
+
session[:facebook_session] = nil
|
42
|
+
@facebook_session = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def new_facebook_session
|
46
|
+
Buddy::Session.create(Buddy.current_config['app_id'], Buddy.current_config['secret'])
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_facebook_session
|
50
|
+
@facebook_session = new_facebook_session
|
51
|
+
@facebook_session.secure!(params[:user_id], params[:oauth_token], params[:expires])
|
52
|
+
@facebook_session.secured?
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_facebook_session
|
56
|
+
session_set = !@facebook_session.blank? && @facebook_session.secured?
|
57
|
+
unless session_set
|
58
|
+
session_set = create_facebook_session
|
59
|
+
session[:facebook_session] = @facebook_session if session_set
|
60
|
+
end
|
61
|
+
if session_set
|
62
|
+
Session.current = @facebook_session
|
63
|
+
end
|
64
|
+
return session_set
|
65
|
+
end
|
66
|
+
|
67
|
+
def ensure_facebook_session
|
68
|
+
return create_new_facebook_session_and_redirect! unless application_is_installed?
|
69
|
+
set_facebook_session || create_new_facebook_session_and_redirect!
|
70
|
+
end
|
71
|
+
|
72
|
+
def default_after_install_url
|
73
|
+
url_for('/')
|
74
|
+
end
|
75
|
+
|
76
|
+
def create_new_facebook_session_and_redirect!
|
77
|
+
session[:facebook_session] = new_facebook_session
|
78
|
+
next_url = defined?(:after_install_url) ? default_after_install_url : after_install_url
|
79
|
+
top_redirect_to session[:facebook_session].install_url({:next => next_url}) if @installation_required
|
80
|
+
end
|
81
|
+
|
82
|
+
def ensure_application_is_installed
|
83
|
+
@installation_required = true
|
84
|
+
ensure_facebook_session
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ::ActionController
|
2
|
+
class Base
|
3
|
+
def self.inherited_with_buddy(subclass)
|
4
|
+
inherited_without_buddy(subclass)
|
5
|
+
#if subclass.to_s == "ApplicationController"
|
6
|
+
subclass.send(:include, Buddy::Rails::Controller)
|
7
|
+
#subclass.helper Buddy::Rails::Helpers
|
8
|
+
#end
|
9
|
+
end
|
10
|
+
class << self
|
11
|
+
alias_method_chain :inherited, :buddy
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# When making get requests, Facebook sends fb_sig parameters both in the query string
|
18
|
+
# and also in the post body. We want to ignore the query string ones because they are one
|
19
|
+
# request out of date
|
20
|
+
# We only do thise when there are POST parameters so that IFrame linkage still works
|
21
|
+
#class ActionController::Request
|
22
|
+
# def query_parameters_with_buddy
|
23
|
+
# if request_parameters.blank?
|
24
|
+
# query_parameters_without_buddy
|
25
|
+
# else
|
26
|
+
# (query_parameters_without_buddy||{}).reject {|key,value| key.to_s =~ /^fb_sig/}
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
|
30
|
+
# alias_method_chain :query_parameters, :buddy
|
31
|
+
#end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Buddy
|
2
|
+
module Rails
|
3
|
+
module UrlHelper
|
4
|
+
def url_for(options = {})
|
5
|
+
options ||= {}
|
6
|
+
opts = case options
|
7
|
+
when Hash
|
8
|
+
options.merge!({ :only_path => true }) #unless options[:canvas] == false
|
9
|
+
else
|
10
|
+
options
|
11
|
+
end
|
12
|
+
url = super(opts)
|
13
|
+
|
14
|
+
if url.include?("http://") #todo: make it better
|
15
|
+
url
|
16
|
+
elsif options.is_a?(Hash) && options[:canvas] == false
|
17
|
+
"#{Buddy.current_config["callback_url"]}#{url}"
|
18
|
+
else
|
19
|
+
"http://apps.facebook.com/#{Buddy.current_config["canvas_page_name"]}#{url}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'buddy'
|
2
|
+
require 'buddy/rails/url_helper'
|
3
|
+
require 'rails'
|
4
|
+
|
5
|
+
module Buddy
|
6
|
+
class Railtie < ::Rails::Railtie
|
7
|
+
initializer "buddy.configure_rails_initialization" do |app|
|
8
|
+
app.config.middleware.insert_before(ActionDispatch::RemoteIp, ::Rack::Facebook::RemoteIp)
|
9
|
+
app.config.middleware.insert_before(ActionDispatch::ParamsParser, ::Rack::Facebook::ParamsParser)
|
10
|
+
app.config.action_controller.asset_host = Buddy.buddy_config['default']['callback_url']
|
11
|
+
|
12
|
+
ActionView::Helpers::UrlHelper.send(:include, Buddy::Rails::UrlHelper)
|
13
|
+
|
14
|
+
Mime::Type.register "text/html", :fbml
|
15
|
+
Mime::Type.register "text/javascript", :fbjs
|
16
|
+
Buddy.logger = ::Rails.logger
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'observer'
|
2
|
+
module Buddy
|
3
|
+
class OAuthException < ArgumentError
|
4
|
+
end
|
5
|
+
|
6
|
+
module Service
|
7
|
+
class << self
|
8
|
+
def call(api_method, params = {}, options = {})
|
9
|
+
Buddy.caller.call(api_method, params, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(resource, params = {})
|
13
|
+
result = GraphApiClient.get(resource, :query => params).parsed_response
|
14
|
+
raise OAuthException.new(result["error"]["message"]) if result["error"]
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
def post(resource, params = {})
|
19
|
+
result = GraphApiClient.post(resource, :query => params).parsed_response
|
20
|
+
raise OAuthException.new(result["error"]["message"]) if result["error"]
|
21
|
+
result
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class GraphApiClient
|
26
|
+
include HTTParty
|
27
|
+
base_uri 'https://graph.facebook.com'
|
28
|
+
end
|
29
|
+
|
30
|
+
class Caller
|
31
|
+
include Observable
|
32
|
+
def call(api_method, params = {}, options = {})
|
33
|
+
begin
|
34
|
+
application = options[:app] || 'default'
|
35
|
+
rescue NoMethodError => e
|
36
|
+
raise ArgumentError.new("app not specified in buddy.yml")
|
37
|
+
end
|
38
|
+
|
39
|
+
changed
|
40
|
+
notify_observers(api_method, params, options)
|
41
|
+
|
42
|
+
result = nil
|
43
|
+
time = Benchmark.realtime do
|
44
|
+
result = MiniFB.call(Buddy.buddy_config[application]["api_key"],
|
45
|
+
Buddy.buddy_config[application]["secret"],
|
46
|
+
api_method,
|
47
|
+
params.stringify_keys)
|
48
|
+
end
|
49
|
+
Buddy.logger.info("Calling #{api_method} (#{params.inspect}) - #{time}")
|
50
|
+
result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Buddy
|
2
|
+
class Session
|
3
|
+
def self.create(app_id = nil, secret_key = nil)
|
4
|
+
app_id ||= self.app_id
|
5
|
+
secret_key ||= self.secret_key
|
6
|
+
raise ArgumentError unless !app_id.nil? && !secret_key.nil?
|
7
|
+
new(app_id, secret_key)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.app_id
|
11
|
+
Buddy.current_config["app_id"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.api_key
|
15
|
+
Buddy.current_config["api_key"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.secret_key
|
19
|
+
Buddy.current_config["secret"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.current
|
23
|
+
Thread.current['facebook_session']
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.current=(session)
|
27
|
+
Thread.current['facebook_session'] = session
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(api_method, params = {}, options = {})
|
31
|
+
params.merge!(:uids => uid, :access_token => access_token)
|
32
|
+
Buddy::Service.call(api_method, params, options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def get(resource, params = {})
|
36
|
+
params.merge!(:access_token => access_token) unless params[:access_token]
|
37
|
+
Buddy::Service.get(resource, params)
|
38
|
+
end
|
39
|
+
|
40
|
+
def post(resource, params = {})
|
41
|
+
params.merge!(:access_token => access_token) unless params[:access_token]
|
42
|
+
Buddy::Service.post(resource, params)
|
43
|
+
end
|
44
|
+
|
45
|
+
def install_url(options = {})
|
46
|
+
"http://www.facebook.com/connect/uiserver.php?app_id=#{Buddy.current_config['app_id']}&next=#{options[:next]}&display=page&locale=de_DE&return_session=0&fbconnect=0&canvas=1&legacy_return=1&method=permissions.request#{"&perms="+Buddy.current_config['perms'] if Buddy.current_config['perms']}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(app_id, secret_key)
|
50
|
+
@app_id = app_id
|
51
|
+
@secret_key = secret_key
|
52
|
+
@uid = nil
|
53
|
+
@access_token = nil
|
54
|
+
@expires = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def secure!(uid, access_token, expires)
|
58
|
+
@uid = uid
|
59
|
+
@access_token = access_token
|
60
|
+
@expires = expires
|
61
|
+
end
|
62
|
+
|
63
|
+
def infinite?
|
64
|
+
@expires == 0
|
65
|
+
end
|
66
|
+
|
67
|
+
def expired?
|
68
|
+
@expires.nil? || (!infinite? && Time.at(@expires) <= Time.now)
|
69
|
+
end
|
70
|
+
|
71
|
+
def secured?
|
72
|
+
!@uid.nil? && !@access_token.nil? && !expired?
|
73
|
+
end
|
74
|
+
|
75
|
+
def user
|
76
|
+
@user ||= Buddy::User.new(@uid, self)
|
77
|
+
end
|
78
|
+
|
79
|
+
def uid
|
80
|
+
@uid
|
81
|
+
end
|
82
|
+
|
83
|
+
def access_token
|
84
|
+
@access_token
|
85
|
+
end
|
86
|
+
|
87
|
+
def expires
|
88
|
+
@expires
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/buddy/user.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Buddy
|
2
|
+
class User
|
3
|
+
FIELDS = [:status, :political, :pic_small, :name, :quotes, :is_app_user, :tv, :profile_update_time, :meeting_sex, :hs_info, :timezone, :relationship_status, :hometown_location, :about_me, :wall_count, :significant_other_id, :pic_big, :music, :work_history, :sex, :religion, :notes_count, :activities, :pic_square, :movies, :has_added_app, :education_history, :birthday, :birthday_date, :first_name, :meeting_for, :last_name, :interests, :current_location, :pic, :books, :affiliations, :locale, :profile_url, :proxied_email, :email_hashes, :allowed_restrictions, :pic_with_logo, :pic_big_with_logo, :pic_small_with_logo, :pic_square_with_logo, :online_presence, :verified, :profile_blurb, :username, :website, :is_blocked, :family, :email]
|
4
|
+
STANDARD_FIELDS = [:uid, :first_name, :last_name, :name, :timezone, :birthday, :sex, :affiliations, :locale, :profile_url, :proxied_email, :email]
|
5
|
+
|
6
|
+
def initialize(uid, session)
|
7
|
+
@uid = uid
|
8
|
+
@session = session
|
9
|
+
end
|
10
|
+
|
11
|
+
def uid
|
12
|
+
@uid
|
13
|
+
end
|
14
|
+
|
15
|
+
alias :facebook_id :uid
|
16
|
+
alias :id :uid
|
17
|
+
|
18
|
+
def to_i
|
19
|
+
@uid
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/buddy.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'openssl'
|
5
|
+
require 'yajl'
|
6
|
+
require 'mini_fb'
|
7
|
+
require 'httparty'
|
8
|
+
|
9
|
+
require 'rack/facebook'
|
10
|
+
|
11
|
+
require 'buddy/user'
|
12
|
+
require 'buddy/session'
|
13
|
+
require 'buddy/service'
|
14
|
+
|
15
|
+
module Buddy
|
16
|
+
@buddy_config = {}
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_accessor :logger, :caller
|
20
|
+
|
21
|
+
def load_configuration(yaml)
|
22
|
+
return false unless File.exist?(yaml)
|
23
|
+
@buddy_config = YAML.load(ERB.new(File.read(yaml)).result)[::Rails.env]
|
24
|
+
self.current_config = buddy_config['default']
|
25
|
+
|
26
|
+
buddy_config
|
27
|
+
end
|
28
|
+
|
29
|
+
def buddy_config
|
30
|
+
@buddy_config
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_asset_host_to_callback_url
|
34
|
+
buddy_config[app]['set_asset_host_to_callback_url']
|
35
|
+
end
|
36
|
+
|
37
|
+
def timeout(app = 'default')
|
38
|
+
buddy_config[app]['timeout']
|
39
|
+
end
|
40
|
+
|
41
|
+
def use_application(api_key)
|
42
|
+
buddy_config.each do |c|
|
43
|
+
if c[1]["api_key"] == api_key
|
44
|
+
return self.current_config = c[1]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def current_config
|
50
|
+
Thread.current['current_buddy_config']
|
51
|
+
end
|
52
|
+
|
53
|
+
def current_config=(config)
|
54
|
+
Thread.current['current_buddy_config'] = config
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
buddy_config = File.join(Bundler.root, "config", "buddy.yml")
|
60
|
+
|
61
|
+
BUDDY = Buddy.load_configuration(buddy_config)
|
62
|
+
Buddy.logger = Rails.logger
|
63
|
+
Buddy.caller = Buddy::Service::Caller.new
|
64
|
+
|
65
|
+
require 'buddy/rails/backwards_compatible_param_checks'
|
66
|
+
require 'buddy/rails/url_helper'
|
67
|
+
require 'buddy/rails/controller'
|
68
|
+
require 'buddy/rails/controller_extensions'
|
69
|
+
|
70
|
+
require 'buddy/railtie'
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Rack
|
2
|
+
# This Rack middleware checks the signature of Facebook params, and
|
3
|
+
# converts them to Ruby objects when appropiate. Also, it converts
|
4
|
+
# the request method from the Facebook POST to the original HTTP
|
5
|
+
# method used by the client.
|
6
|
+
#
|
7
|
+
# If the signature is wrong, it returns a "400 Invalid Facebook Signature".
|
8
|
+
#
|
9
|
+
# Optionally, it can take a block that receives the Rack environment
|
10
|
+
# and returns a value that evaluates to true when we want the middleware to
|
11
|
+
# be executed for the specific request.
|
12
|
+
#
|
13
|
+
# == Usage
|
14
|
+
#
|
15
|
+
# In your config.ru:
|
16
|
+
#
|
17
|
+
# require 'rack/facebook'
|
18
|
+
# use Rack::Facebook, "my_facebook_secret_key"
|
19
|
+
#
|
20
|
+
# Using a block condition:
|
21
|
+
#
|
22
|
+
# use Rack::Facebook, "my_facebook_secret_key" do |env|
|
23
|
+
# env['REQUEST_URI'] =~ /^\/facebook_only/
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
|
27
|
+
module Facebook
|
28
|
+
class RemoteIp
|
29
|
+
def initialize(app)
|
30
|
+
@app = app
|
31
|
+
end
|
32
|
+
|
33
|
+
def call(env)
|
34
|
+
env['REMOTE_ADDR'] = env['X-FB-USER-REMOTE-ADDR'] if env['X-FB-USER-REMOTE-ADDR']
|
35
|
+
@app.call(env)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class ParamsParser
|
40
|
+
def initialize(app, &condition)
|
41
|
+
@app = app
|
42
|
+
@condition = condition
|
43
|
+
end
|
44
|
+
|
45
|
+
def call(env)
|
46
|
+
return @app.call(env) unless @condition.nil? || @condition.call(env)
|
47
|
+
|
48
|
+
request = Rack::Request.new(env)
|
49
|
+
|
50
|
+
signed_request = request.params["signed_request"]
|
51
|
+
if signed_request
|
52
|
+
signature, signed_params = signed_request.split('.')
|
53
|
+
|
54
|
+
unless signed_request_is_valid?(Buddy.current_config['secret'], signature, signed_params)
|
55
|
+
return Rack::Response.new(["Invalid Facebook signature"], 400).finish
|
56
|
+
end
|
57
|
+
|
58
|
+
signed_params = Yajl::Parser.new.parse(base64_url_decode(signed_params))
|
59
|
+
signed_params.each do |k,v|
|
60
|
+
request.params[k] = v
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
@app.call(env)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# This function takes the app secret and the signed request, and verifies if the request is valid.
|
70
|
+
def signed_request_is_valid?(secret, signature, params)
|
71
|
+
sig = base64_url_decode(signature)
|
72
|
+
expected_sig = OpenSSL::HMAC.digest('SHA256', secret, params.tr("-_", "+/"))
|
73
|
+
return sig == expected_sig
|
74
|
+
end
|
75
|
+
|
76
|
+
# Ruby's implementation of base64 decoding reads the string in multiples of 6 and ignores any extra bytes.
|
77
|
+
# Since facebook does not take this into account, this function fills any string with white spaces up to
|
78
|
+
# the point where it becomes divisible by 6, then it replaces '-' with '+' and '_' with '/' (URL-safe decoding),
|
79
|
+
# and decodes the result.
|
80
|
+
def base64_url_decode(str)
|
81
|
+
str = str + "=" * (6 - str.size % 6) unless str.size % 6 == 0
|
82
|
+
return Base64.decode64(str.tr("-_", "+/"))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/test/test_buddy.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mocha'
|
3
|
+
|
4
|
+
class BuddyTests < Test::Unit::TestCase
|
5
|
+
def test_user_getinfo
|
6
|
+
result = [{"first_name"=>"Ole", "name"=>"Foo Bar", "uid"=>123456789}]
|
7
|
+
|
8
|
+
Buddy::Service.expects(:call).with('Users.getInfo', {:uids => '686373959', :fields => 'uid, name, first_name'}).returns(result)
|
9
|
+
end
|
10
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: buddy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 4
|
8
|
+
- 0
|
9
|
+
version: 0.4.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ole Riesenberg
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-09-08 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: mini_fb
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 2
|
31
|
+
- 2
|
32
|
+
version: 0.2.2
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: yajl-ruby
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: httparty
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
type: :runtime
|
60
|
+
version_requirements: *id003
|
61
|
+
description: buddybrand's facebook library
|
62
|
+
email: labs@buddybrand.de
|
63
|
+
executables: []
|
64
|
+
|
65
|
+
extensions: []
|
66
|
+
|
67
|
+
extra_rdoc_files:
|
68
|
+
- README.md
|
69
|
+
files:
|
70
|
+
- lib/buddy.rb
|
71
|
+
- lib/buddy/rails/backwards_compatible_param_checks.rb
|
72
|
+
- lib/buddy/rails/controller.rb
|
73
|
+
- lib/buddy/rails/controller_extensions.rb
|
74
|
+
- lib/buddy/rails/url_helper.rb
|
75
|
+
- lib/buddy/railtie.rb
|
76
|
+
- lib/buddy/service.rb
|
77
|
+
- lib/buddy/session.rb
|
78
|
+
- lib/buddy/user.rb
|
79
|
+
- lib/rack/facebook.rb
|
80
|
+
- test/test_buddy.rb
|
81
|
+
- README.md
|
82
|
+
has_rdoc: true
|
83
|
+
homepage: http://buddybrand.de
|
84
|
+
licenses: []
|
85
|
+
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options:
|
88
|
+
- --charset=UTF-8
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
version: "0"
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
segments:
|
105
|
+
- 0
|
106
|
+
version: "0"
|
107
|
+
requirements: []
|
108
|
+
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 1.3.7
|
111
|
+
signing_key:
|
112
|
+
specification_version: 3
|
113
|
+
summary: buddybrand's facebook library
|
114
|
+
test_files:
|
115
|
+
- test/test_buddy.rb
|