taweili-facebooker 1.0.37
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.
- data/.autotest +15 -0
- data/CHANGELOG.rdoc +24 -0
- data/COPYING.rdoc +19 -0
- data/Manifest.txt +133 -0
- data/README.rdoc +104 -0
- data/Rakefile +85 -0
- data/TODO.rdoc +4 -0
- data/examples/desktop_login.rb +14 -0
- data/facebooker.gemspec +38 -0
- data/generators/facebook/facebook_generator.rb +14 -0
- data/generators/facebook/templates/config/facebooker.yml +49 -0
- data/generators/facebook/templates/public/javascripts/facebooker.js +83 -0
- data/generators/facebook_controller/USAGE +33 -0
- data/generators/facebook_controller/facebook_controller_generator.rb +40 -0
- data/generators/facebook_controller/templates/controller.rb +7 -0
- data/generators/facebook_controller/templates/functional_test.rb +11 -0
- data/generators/facebook_controller/templates/helper.rb +2 -0
- data/generators/facebook_controller/templates/view.fbml.erb +2 -0
- data/generators/facebook_controller/templates/view.html.erb +2 -0
- data/generators/facebook_publisher/facebook_publisher_generator.rb +14 -0
- data/generators/facebook_publisher/templates/create_facebook_templates.rb +15 -0
- data/generators/facebook_publisher/templates/publisher.rb +3 -0
- data/generators/facebook_scaffold/USAGE +27 -0
- data/generators/facebook_scaffold/facebook_scaffold_generator.rb +118 -0
- data/generators/facebook_scaffold/templates/controller.rb +93 -0
- data/generators/facebook_scaffold/templates/facebook_style.css +2579 -0
- data/generators/facebook_scaffold/templates/functional_test.rb +89 -0
- data/generators/facebook_scaffold/templates/helper.rb +2 -0
- data/generators/facebook_scaffold/templates/layout.fbml.erb +6 -0
- data/generators/facebook_scaffold/templates/layout.html.erb +17 -0
- data/generators/facebook_scaffold/templates/style.css +74 -0
- data/generators/facebook_scaffold/templates/view_edit.fbml.erb +13 -0
- data/generators/facebook_scaffold/templates/view_edit.html.erb +18 -0
- data/generators/facebook_scaffold/templates/view_index.fbml.erb +24 -0
- data/generators/facebook_scaffold/templates/view_index.html.erb +24 -0
- data/generators/facebook_scaffold/templates/view_new.fbml.erb +12 -0
- data/generators/facebook_scaffold/templates/view_new.html.erb +17 -0
- data/generators/facebook_scaffold/templates/view_show.fbml.erb +10 -0
- data/generators/facebook_scaffold/templates/view_show.html.erb +10 -0
- data/generators/publisher/publisher_generator.rb +14 -0
- data/generators/xd_receiver/templates/xd_receiver.html +10 -0
- data/generators/xd_receiver/xd_receiver_generator.rb +10 -0
- data/init.rb +25 -0
- data/install.rb +12 -0
- data/lib/facebooker/adapters/adapter_base.rb +91 -0
- data/lib/facebooker/adapters/bebo_adapter.rb +77 -0
- data/lib/facebooker/adapters/facebook_adapter.rb +52 -0
- data/lib/facebooker/admin.rb +42 -0
- data/lib/facebooker/batch_request.rb +45 -0
- data/lib/facebooker/data.rb +57 -0
- data/lib/facebooker/feed.rb +78 -0
- data/lib/facebooker/logging.rb +44 -0
- data/lib/facebooker/mobile.rb +20 -0
- data/lib/facebooker/mock/service.rb +50 -0
- data/lib/facebooker/mock/session.rb +18 -0
- data/lib/facebooker/model.rb +139 -0
- data/lib/facebooker/models/affiliation.rb +10 -0
- data/lib/facebooker/models/album.rb +11 -0
- data/lib/facebooker/models/applicationproperties.rb +39 -0
- data/lib/facebooker/models/applicationrestrictions.rb +10 -0
- data/lib/facebooker/models/cookie.rb +10 -0
- data/lib/facebooker/models/education_info.rb +11 -0
- data/lib/facebooker/models/event.rb +28 -0
- data/lib/facebooker/models/friend_list.rb +16 -0
- data/lib/facebooker/models/group.rb +36 -0
- data/lib/facebooker/models/info_item.rb +10 -0
- data/lib/facebooker/models/info_section.rb +10 -0
- data/lib/facebooker/models/location.rb +8 -0
- data/lib/facebooker/models/notifications.rb +17 -0
- data/lib/facebooker/models/page.rb +28 -0
- data/lib/facebooker/models/photo.rb +19 -0
- data/lib/facebooker/models/tag.rb +12 -0
- data/lib/facebooker/models/user.rb +497 -0
- data/lib/facebooker/models/video.rb +9 -0
- data/lib/facebooker/models/work_info.rb +10 -0
- data/lib/facebooker/parser.rb +650 -0
- data/lib/facebooker/rails/backwards_compatible_param_checks.rb +31 -0
- data/lib/facebooker/rails/controller.rb +337 -0
- data/lib/facebooker/rails/cucumber/world.rb +46 -0
- data/lib/facebooker/rails/cucumber.rb +28 -0
- data/lib/facebooker/rails/extensions/action_controller.rb +48 -0
- data/lib/facebooker/rails/extensions/rack_setup.rb +6 -0
- data/lib/facebooker/rails/extensions/routing.rb +15 -0
- data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
- data/lib/facebooker/rails/facebook_pretty_errors.rb +22 -0
- data/lib/facebooker/rails/facebook_request_fix.rb +30 -0
- data/lib/facebooker/rails/facebook_request_fix_2-3.rb +31 -0
- data/lib/facebooker/rails/facebook_session_handling.rb +68 -0
- data/lib/facebooker/rails/facebook_url_helper.rb +192 -0
- data/lib/facebooker/rails/facebook_url_rewriting.rb +60 -0
- data/lib/facebooker/rails/helpers/fb_connect.rb +118 -0
- data/lib/facebooker/rails/helpers.rb +780 -0
- data/lib/facebooker/rails/integration_session.rb +38 -0
- data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
- data/lib/facebooker/rails/publisher.rb +554 -0
- data/lib/facebooker/rails/routing.rb +49 -0
- data/lib/facebooker/rails/test_helpers.rb +68 -0
- data/lib/facebooker/rails/utilities.rb +22 -0
- data/lib/facebooker/server_cache.rb +24 -0
- data/lib/facebooker/service.rb +102 -0
- data/lib/facebooker/session.rb +606 -0
- data/lib/facebooker/version.rb +9 -0
- data/lib/facebooker.rb +180 -0
- data/lib/net/http_multipart_post.rb +123 -0
- data/lib/rack/facebook.rb +77 -0
- data/lib/tasks/facebooker.rake +18 -0
- data/lib/tasks/tunnel.rake +46 -0
- data/rails/init.rb +1 -0
- data/setup.rb +1585 -0
- data/templates/layout.erb +24 -0
- data/test/facebooker/adapters_test.rb +96 -0
- data/test/facebooker/admin_test.rb +102 -0
- data/test/facebooker/batch_request_test.rb +83 -0
- data/test/facebooker/data_test.rb +86 -0
- data/test/facebooker/logging_test.rb +43 -0
- data/test/facebooker/mobile_test.rb +45 -0
- data/test/facebooker/model_test.rb +133 -0
- data/test/facebooker/models/event_test.rb +15 -0
- data/test/facebooker/models/photo_test.rb +16 -0
- data/test/facebooker/models/user_test.rb +343 -0
- data/test/facebooker/rails/facebook_request_fix_2-3_test.rb +24 -0
- data/test/facebooker/rails/facebook_url_rewriting_test.rb +39 -0
- data/test/facebooker/rails/publisher_test.rb +481 -0
- data/test/facebooker/rails_integration_test.rb +1398 -0
- data/test/facebooker/server_cache_test.rb +44 -0
- data/test/facebooker/session_test.rb +614 -0
- data/test/facebooker_test.rb +951 -0
- data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
- data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
- data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
- data/test/net/http_multipart_post_test.rb +52 -0
- data/test/rack/facebook_test.rb +61 -0
- data/test/rails_test_helper.rb +27 -0
- data/test/test_helper.rb +74 -0
- metadata +232 -0
data/lib/facebooker.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
unless defined?(ActiveSupport) and defined?(ActiveSupport::JSON)
|
2
|
+
require 'json'
|
3
|
+
module Facebooker
|
4
|
+
def self.json_decode(str)
|
5
|
+
JSON.parse(str)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.json_encode(o)
|
9
|
+
JSON.dump(o)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
else
|
13
|
+
module Facebooker
|
14
|
+
def self.json_decode(str)
|
15
|
+
ActiveSupport::JSON.decode(str)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.json_encode(o)
|
19
|
+
ActiveSupport::JSON.encode(o)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'zlib'
|
25
|
+
require 'digest/md5'
|
26
|
+
|
27
|
+
module Facebooker
|
28
|
+
|
29
|
+
@facebooker_configuration = {}
|
30
|
+
@current_adapter = nil
|
31
|
+
@set_asset_host_to_callback_url = true
|
32
|
+
@path_prefix = nil
|
33
|
+
@use_curl = false
|
34
|
+
|
35
|
+
class << self
|
36
|
+
|
37
|
+
def load_configuration(facebooker_yaml_file)
|
38
|
+
if File.exist?(facebooker_yaml_file)
|
39
|
+
if defined? RAILS_ENV
|
40
|
+
config = YAML.load_file(facebooker_yaml_file)[RAILS_ENV]
|
41
|
+
else
|
42
|
+
config = YAML.load_file(facebooker_yaml_file)
|
43
|
+
end
|
44
|
+
apply_configuration(config)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Sets the Facebook environment based on a hash of options.
|
49
|
+
# By default the hash passed in is loaded from facebooker.yml, but it can also be passed in
|
50
|
+
# manually every request to run multiple Facebook apps off one Rails app.
|
51
|
+
def apply_configuration(config)
|
52
|
+
ENV['FACEBOOK_API_KEY'] = config['api_key']
|
53
|
+
ENV['FACEBOOK_SECRET_KEY'] = config['secret_key']
|
54
|
+
ENV['FACEBOOKER_RELATIVE_URL_ROOT'] = config['canvas_page_name']
|
55
|
+
ENV['FACEBOOKER_API'] = config['api']
|
56
|
+
if config.has_key?('set_asset_host_to_callback_url')
|
57
|
+
Facebooker.set_asset_host_to_callback_url = config['set_asset_host_to_callback_url']
|
58
|
+
end
|
59
|
+
if Object.const_defined?("ActionController") and Facebooker.set_asset_host_to_callback_url
|
60
|
+
ActionController::Base.asset_host = config['callback_url']
|
61
|
+
end
|
62
|
+
Facebooker.timeout = config['timeout']
|
63
|
+
@facebooker_configuration = config
|
64
|
+
end
|
65
|
+
|
66
|
+
def facebooker_config
|
67
|
+
@facebooker_configuration
|
68
|
+
end
|
69
|
+
|
70
|
+
# TODO: This should be converted to attr_accessor, but we need to
|
71
|
+
# get all the require statements at the top of the file to work.
|
72
|
+
|
73
|
+
# Set the current adapter
|
74
|
+
attr_writer :current_adapter
|
75
|
+
|
76
|
+
# Get the current adapter
|
77
|
+
def current_adapter
|
78
|
+
@current_adapter || Facebooker::AdapterBase.default_adapter
|
79
|
+
end
|
80
|
+
|
81
|
+
def load_adapter(params)
|
82
|
+
self.current_adapter = Facebooker::AdapterBase.load_adapter(params)
|
83
|
+
end
|
84
|
+
|
85
|
+
def facebook_path_prefix=(path)
|
86
|
+
current_adapter.facebook_path_prefix = path
|
87
|
+
end
|
88
|
+
|
89
|
+
# Default is canvas_page_name in yml file
|
90
|
+
def facebook_path_prefix
|
91
|
+
current_adapter.facebook_path_prefix
|
92
|
+
end
|
93
|
+
|
94
|
+
def is_for?(application_container)
|
95
|
+
current_adapter.is_for?(application_container)
|
96
|
+
end
|
97
|
+
|
98
|
+
attr_accessor :set_asset_host_to_callback_url
|
99
|
+
attr_accessor :use_curl
|
100
|
+
alias :use_curl? :use_curl
|
101
|
+
|
102
|
+
def timeout=(val)
|
103
|
+
@timeout = val.to_i
|
104
|
+
end
|
105
|
+
|
106
|
+
def timeout
|
107
|
+
@timeout
|
108
|
+
end
|
109
|
+
|
110
|
+
[:api_key,:secret_key, :www_server_base_url,:login_url_base,:install_url_base,:api_rest_path,:api_server_base,:api_server_base_url,:canvas_server_base, :video_server_base].each do |delegated_method|
|
111
|
+
define_method(delegated_method){ return current_adapter.send(delegated_method)}
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
attr_reader :path_prefix
|
116
|
+
|
117
|
+
|
118
|
+
# Set the asset path to the canvas path for just this one request
|
119
|
+
# by definition, we will make this a canvas request
|
120
|
+
def with_asset_path_for_canvas
|
121
|
+
original_asset_host = ActionController::Base.asset_host
|
122
|
+
begin
|
123
|
+
ActionController::Base.asset_host = Facebooker.api_server_base_url
|
124
|
+
request_for_canvas(true) do
|
125
|
+
yield
|
126
|
+
end
|
127
|
+
ensure
|
128
|
+
ActionController::Base.asset_host = original_asset_host
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# If this request is_canvas_request
|
133
|
+
# then use the application name as the url root
|
134
|
+
def request_for_canvas(is_canvas_request)
|
135
|
+
original_path_prefix = @path_prefix
|
136
|
+
begin
|
137
|
+
@path_prefix = facebook_path_prefix if is_canvas_request
|
138
|
+
yield
|
139
|
+
ensure
|
140
|
+
@path_prefix = original_path_prefix
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
require 'facebooker/batch_request'
|
147
|
+
require 'facebooker/feed'
|
148
|
+
require 'facebooker/logging'
|
149
|
+
require 'facebooker/model'
|
150
|
+
require 'facebooker/parser'
|
151
|
+
require 'facebooker/service'
|
152
|
+
require 'facebooker/server_cache'
|
153
|
+
require 'facebooker/data'
|
154
|
+
require 'facebooker/admin'
|
155
|
+
require 'facebooker/mobile'
|
156
|
+
require 'facebooker/session'
|
157
|
+
require 'facebooker/version'
|
158
|
+
require 'facebooker/models/location'
|
159
|
+
require 'facebooker/models/affiliation'
|
160
|
+
require 'facebooker/models/album'
|
161
|
+
require 'facebooker/models/education_info'
|
162
|
+
require 'facebooker/models/work_info'
|
163
|
+
require 'facebooker/models/event'
|
164
|
+
require 'facebooker/models/group'
|
165
|
+
require 'facebooker/models/notifications'
|
166
|
+
require 'facebooker/models/page'
|
167
|
+
require 'facebooker/models/photo'
|
168
|
+
require 'facebooker/models/cookie'
|
169
|
+
require 'facebooker/models/applicationproperties'
|
170
|
+
require 'facebooker/models/applicationrestrictions'
|
171
|
+
require 'facebooker/models/tag'
|
172
|
+
require 'facebooker/models/user'
|
173
|
+
require 'facebooker/models/info_item'
|
174
|
+
require 'facebooker/models/info_section'
|
175
|
+
require 'facebooker/models/permission'
|
176
|
+
require 'facebooker/models/friend_list'
|
177
|
+
require 'facebooker/models/video'
|
178
|
+
require 'facebooker/adapters/adapter_base'
|
179
|
+
require 'facebooker/adapters/facebook_adapter'
|
180
|
+
require 'facebooker/adapters/bebo_adapter'
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Net
|
4
|
+
class HTTP
|
5
|
+
class << self
|
6
|
+
def post_multipart_form(url, params)
|
7
|
+
MultipartPost.new(url, params).post
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class MultipartPostFile
|
12
|
+
def initialize(filename=nil, content_type=nil, data=nil)
|
13
|
+
@filename = filename
|
14
|
+
@content_type = content_type
|
15
|
+
@data = data
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :filename
|
19
|
+
attr_accessor :content_type
|
20
|
+
attr_accessor :data
|
21
|
+
end
|
22
|
+
|
23
|
+
class MultipartPost
|
24
|
+
def initialize(url, params)
|
25
|
+
@url = url
|
26
|
+
@multipart_post_files = extract_file_parameters_from(params)
|
27
|
+
@params = extract_non_file_parameters_from(params)
|
28
|
+
end
|
29
|
+
|
30
|
+
def post
|
31
|
+
req = Post.new(url.path)
|
32
|
+
req.body = body
|
33
|
+
req.content_type = content_type
|
34
|
+
req.basic_auth url.user, url.password if url.user
|
35
|
+
Net::HTTP.new(url.host, url.port).start {|http|
|
36
|
+
http.request(req)
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
BOUNDARY = "MichaelNiessnerIsSuperDuperAwesome"
|
41
|
+
|
42
|
+
protected
|
43
|
+
attr_reader :url, :params, :multipart_post_files
|
44
|
+
|
45
|
+
def extract_file_parameters_from(hash)
|
46
|
+
hash.reject{|key, value| !multipart_post_file?(value)}
|
47
|
+
end
|
48
|
+
|
49
|
+
def extract_non_file_parameters_from(hash)
|
50
|
+
hash.reject{|key, value| multipart_post_file?(value)}
|
51
|
+
end
|
52
|
+
|
53
|
+
def multipart_post_file?(object)
|
54
|
+
object.respond_to?(:content_type) &&
|
55
|
+
object.respond_to?(:data) &&
|
56
|
+
object.respond_to?(:filename)
|
57
|
+
end
|
58
|
+
|
59
|
+
def content_type
|
60
|
+
"multipart/form-data; boundary=#{BOUNDARY}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def body
|
64
|
+
encode_parameters + encode_multipart_post_files + final_boundary
|
65
|
+
end
|
66
|
+
|
67
|
+
def encode_multipart_post_files
|
68
|
+
return "" if multipart_post_files.empty?
|
69
|
+
if multipart_post_files.size == 1
|
70
|
+
name = multipart_post_files.keys.first
|
71
|
+
file = multipart_post_files.values.first
|
72
|
+
encode_multipart_post_file(name, file)
|
73
|
+
else
|
74
|
+
raise "Currently more than 1 file upload is not supported."
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def encode_multipart_post_file(name, multipart_post_file)
|
79
|
+
parameter_boundary +
|
80
|
+
disposition_with_filename(name, multipart_post_file.filename) +
|
81
|
+
file_content_type(multipart_post_file.content_type) +
|
82
|
+
multipart_post_file.data +
|
83
|
+
"\r\n"
|
84
|
+
end
|
85
|
+
|
86
|
+
def encode_parameters
|
87
|
+
params.sort_by{|key, value| key.to_s}.map{|key, value| encode_parameter(key, value)}.join
|
88
|
+
end
|
89
|
+
|
90
|
+
def encode_parameter(key, value)
|
91
|
+
parameter_boundary + disposition_with_name(key) + value.to_s + "\r\n"
|
92
|
+
end
|
93
|
+
|
94
|
+
def file_content_type(string)
|
95
|
+
"Content-Type: #{string}\r\n\r\n"
|
96
|
+
end
|
97
|
+
|
98
|
+
def disposition_with_filename(name, filename)
|
99
|
+
if name.nil?
|
100
|
+
disposition("filename=\"#{filename}\"")
|
101
|
+
else
|
102
|
+
disposition("name=\"#{name}\"; filename=\"#{filename}\"")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def disposition_with_name(name)
|
107
|
+
disposition("name=\"#{name}\"\r\n")
|
108
|
+
end
|
109
|
+
|
110
|
+
def disposition(attribute)
|
111
|
+
"Content-Disposition: form-data; #{attribute}\r\n"
|
112
|
+
end
|
113
|
+
|
114
|
+
def parameter_boundary
|
115
|
+
"--#{BOUNDARY}\r\n"
|
116
|
+
end
|
117
|
+
|
118
|
+
def final_boundary
|
119
|
+
"--#{BOUNDARY}--\r\n"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,77 @@
|
|
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
|
+
class Facebook
|
27
|
+
def initialize(app, secret_key, &condition)
|
28
|
+
@app = app
|
29
|
+
@secret_key = secret_key
|
30
|
+
@condition = condition
|
31
|
+
end
|
32
|
+
|
33
|
+
def call(env)
|
34
|
+
if @condition.nil? || @condition.call(env)
|
35
|
+
request = Rack::Request.new(env)
|
36
|
+
fb_params = extract_fb_sig_params(request.POST)
|
37
|
+
unless fb_params.empty?
|
38
|
+
unless signature_is_valid?(fb_params, request.POST['fb_sig'])
|
39
|
+
return Rack::Response.new(["Invalid Facebook signature"], 400).finish
|
40
|
+
end
|
41
|
+
env['REQUEST_METHOD'] = fb_params["request_method"] if fb_params["request_method"]
|
42
|
+
convert_parameters!(request.POST)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
@app.call(env)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def extract_fb_sig_params(params)
|
51
|
+
params.inject({}) do |collection, (param, value)|
|
52
|
+
collection[param.sub(/^fb_sig_/, '')] = value if param[0,7] == 'fb_sig_'
|
53
|
+
collection
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def signature_is_valid?(fb_params, actual_sig)
|
58
|
+
raw_string = fb_params.map{ |*args| args.join('=') }.sort.join
|
59
|
+
expected_signature = Digest::MD5.hexdigest([raw_string, @secret_key].join)
|
60
|
+
actual_sig == expected_signature
|
61
|
+
end
|
62
|
+
|
63
|
+
def convert_parameters!(params)
|
64
|
+
|
65
|
+
params.each do |key, value|
|
66
|
+
case key
|
67
|
+
when 'fb_sig_added', 'fb_sig_in_canvas', 'fb_sig_in_new_facebook', 'fb_sig_position_fix', 'fb_sig_is_ajax'
|
68
|
+
params[key] = value == "1"
|
69
|
+
when 'fb_sig_expires', 'fb_sig_profile_update_time', 'fb_sig_time'
|
70
|
+
params[key] = value == "0" ? nil : Time.at(value.to_f)
|
71
|
+
when 'fb_sig_friends'
|
72
|
+
params[key] = value.split(',')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
namespace :facebooker do
|
4
|
+
|
5
|
+
desc "Create a basic facebooker.yml configuration file"
|
6
|
+
task :setup => :environment do
|
7
|
+
facebook_config = File.join(RAILS_ROOT,"config","facebooker.yml")
|
8
|
+
unless File.exist?(facebook_config)
|
9
|
+
FileUtils.cp File.join(RAILS_ROOT,"vendor", "plugins", "facebooker", "facebooker.yml.tpl"), facebook_config
|
10
|
+
puts "Ensure 'GatewayPorts yes' is enabled in the remote development server's sshd config when using any of the facebooker:tunnel:*' rake tasks"
|
11
|
+
puts "Configuration created in #{RAILS_ROOT}/config/facebooker.yml"
|
12
|
+
else
|
13
|
+
puts "#{RAILS_ROOT}/config/facebooker.yml already exists"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
namespace :facebooker do
|
2
|
+
|
3
|
+
tunnel_ns = namespace :tunnel do
|
4
|
+
# Courtesy of Christopher Haupt
|
5
|
+
# http://www.BuildingWebApps.com
|
6
|
+
# http://www.LearningRails.com
|
7
|
+
desc "Create a reverse ssh tunnel from a public server to a private development server."
|
8
|
+
task :start => [ :environment, :config ] do
|
9
|
+
puts @notification
|
10
|
+
system @ssh_command
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Create a reverse ssh tunnel in the background. Requires ssh keys to be setup."
|
14
|
+
task :background_start => [ :environment, :config ] do
|
15
|
+
puts @notification
|
16
|
+
system "#{@ssh_command} > /dev/null 2>&1 &"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Adapted from Evan Weaver: http://blog.evanweaver.com/articles/2007/07/13/developing-a-facebook-app-locally/
|
20
|
+
desc "Check if reverse tunnel is running"
|
21
|
+
task :status => [ :environment, :config ] do
|
22
|
+
if `ssh #{@public_host} -l #{@public_host_username} netstat -an | egrep "tcp.*:#{@public_port}.*LISTEN" | wc`.to_i > 0
|
23
|
+
puts "Seems ok"
|
24
|
+
else
|
25
|
+
puts "Down"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
task :config => :environment do
|
30
|
+
facebook_config = File.dirname(__FILE__) + '/../../../../../config/facebooker.yml'
|
31
|
+
FACEBOOKER = YAML.load_file(facebook_config)[RAILS_ENV]
|
32
|
+
@public_host_username = FACEBOOKER['tunnel']['public_host_username']
|
33
|
+
@public_host = FACEBOOKER['tunnel']['public_host']
|
34
|
+
@public_port = FACEBOOKER['tunnel']['public_port']
|
35
|
+
@local_port = FACEBOOKER['tunnel']['local_port']
|
36
|
+
@ssh_port = FACEBOOKER['tunnel']['ssh_port'] || 22
|
37
|
+
@server_alive_interval = FACEBOOKER['tunnel']['server_alive_interval'] || 0
|
38
|
+
@notification = "Starting tunnel #{@public_host}:#{@public_port} to 0.0.0.0:#{@local_port}"
|
39
|
+
@notification << " using SSH port #{@ssh_port}" unless @ssh_port == 22
|
40
|
+
# "GatewayPorts yes" needs to be enabled in the remote's sshd config
|
41
|
+
@ssh_command = %Q[ssh -v -p #{@ssh_port} -nNT4 -o "ServerAliveInterval #{@server_alive_interval}" -R *:#{@public_port}:localhost:#{@local_port} #{@public_host_username}@#{@public_host}]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
desc "Create a reverse ssh tunnel from a public server to a private development server."
|
45
|
+
task :tunnel => tunnel_ns[:start]
|
46
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'../init.rb')
|