mborromeo-facebooker 1.0.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. data/CHANGELOG.rdoc +17 -0
  2. data/COPYING.rdoc +19 -0
  3. data/README.rdoc +104 -0
  4. data/Rakefile +86 -0
  5. data/TODO.rdoc +4 -0
  6. data/generators/facebook/facebook_generator.rb +14 -0
  7. data/generators/facebook/templates/config/facebooker.yml +46 -0
  8. data/generators/facebook/templates/public/javascripts/facebooker.js +99 -0
  9. data/generators/facebook_controller/USAGE +33 -0
  10. data/generators/facebook_controller/facebook_controller_generator.rb +40 -0
  11. data/generators/facebook_controller/templates/controller.rb +7 -0
  12. data/generators/facebook_controller/templates/functional_test.rb +11 -0
  13. data/generators/facebook_controller/templates/helper.rb +2 -0
  14. data/generators/facebook_controller/templates/view.fbml.erb +2 -0
  15. data/generators/facebook_controller/templates/view.html.erb +2 -0
  16. data/generators/facebook_publisher/facebook_publisher_generator.rb +14 -0
  17. data/generators/facebook_publisher/templates/create_facebook_templates.rb +15 -0
  18. data/generators/facebook_publisher/templates/publisher.rb +3 -0
  19. data/generators/facebook_scaffold/USAGE +27 -0
  20. data/generators/facebook_scaffold/facebook_scaffold_generator.rb +118 -0
  21. data/generators/facebook_scaffold/templates/controller.rb +93 -0
  22. data/generators/facebook_scaffold/templates/facebook_style.css +2579 -0
  23. data/generators/facebook_scaffold/templates/functional_test.rb +89 -0
  24. data/generators/facebook_scaffold/templates/helper.rb +2 -0
  25. data/generators/facebook_scaffold/templates/layout.fbml.erb +6 -0
  26. data/generators/facebook_scaffold/templates/layout.html.erb +17 -0
  27. data/generators/facebook_scaffold/templates/style.css +74 -0
  28. data/generators/facebook_scaffold/templates/view_edit.fbml.erb +13 -0
  29. data/generators/facebook_scaffold/templates/view_edit.html.erb +18 -0
  30. data/generators/facebook_scaffold/templates/view_index.fbml.erb +24 -0
  31. data/generators/facebook_scaffold/templates/view_index.html.erb +24 -0
  32. data/generators/facebook_scaffold/templates/view_new.fbml.erb +12 -0
  33. data/generators/facebook_scaffold/templates/view_new.html.erb +17 -0
  34. data/generators/facebook_scaffold/templates/view_show.fbml.erb +10 -0
  35. data/generators/facebook_scaffold/templates/view_show.html.erb +10 -0
  36. data/generators/publisher/publisher_generator.rb +14 -0
  37. data/generators/xd_receiver/templates/xd_receiver.html +10 -0
  38. data/generators/xd_receiver/xd_receiver_generator.rb +9 -0
  39. data/init.rb +23 -0
  40. data/install.rb +12 -0
  41. data/lib/facebooker/adapters/adapter_base.rb +90 -0
  42. data/lib/facebooker/adapters/bebo_adapter.rb +75 -0
  43. data/lib/facebooker/adapters/facebook_adapter.rb +52 -0
  44. data/lib/facebooker/admin.rb +42 -0
  45. data/lib/facebooker/batch_request.rb +44 -0
  46. data/lib/facebooker/data.rb +57 -0
  47. data/lib/facebooker/feed.rb +78 -0
  48. data/lib/facebooker/logging.rb +51 -0
  49. data/lib/facebooker/mobile.rb +20 -0
  50. data/lib/facebooker/mock/service.rb +50 -0
  51. data/lib/facebooker/mock/session.rb +18 -0
  52. data/lib/facebooker/model.rb +137 -0
  53. data/lib/facebooker/models/affiliation.rb +10 -0
  54. data/lib/facebooker/models/album.rb +11 -0
  55. data/lib/facebooker/models/applicationproperties.rb +39 -0
  56. data/lib/facebooker/models/applicationrestrictions.rb +10 -0
  57. data/lib/facebooker/models/cookie.rb +10 -0
  58. data/lib/facebooker/models/education_info.rb +11 -0
  59. data/lib/facebooker/models/event.rb +28 -0
  60. data/lib/facebooker/models/friend_list.rb +16 -0
  61. data/lib/facebooker/models/group.rb +36 -0
  62. data/lib/facebooker/models/info_item.rb +10 -0
  63. data/lib/facebooker/models/info_section.rb +10 -0
  64. data/lib/facebooker/models/location.rb +8 -0
  65. data/lib/facebooker/models/notifications.rb +17 -0
  66. data/lib/facebooker/models/page.rb +27 -0
  67. data/lib/facebooker/models/photo.rb +12 -0
  68. data/lib/facebooker/models/tag.rb +12 -0
  69. data/lib/facebooker/models/user.rb +461 -0
  70. data/lib/facebooker/models/video.rb +9 -0
  71. data/lib/facebooker/models/work_info.rb +9 -0
  72. data/lib/facebooker/parser.rb +603 -0
  73. data/lib/facebooker/rails/controller.rb +303 -0
  74. data/lib/facebooker/rails/cucumber/world.rb +46 -0
  75. data/lib/facebooker/rails/cucumber.rb +28 -0
  76. data/lib/facebooker/rails/extensions/action_controller.rb +48 -0
  77. data/lib/facebooker/rails/extensions/rack_setup.rb +2 -0
  78. data/lib/facebooker/rails/extensions/routing.rb +15 -0
  79. data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
  80. data/lib/facebooker/rails/facebook_pretty_errors.rb +22 -0
  81. data/lib/facebooker/rails/facebook_request_fix.rb +24 -0
  82. data/lib/facebooker/rails/facebook_session_handling.rb +69 -0
  83. data/lib/facebooker/rails/facebook_url_helper.rb +192 -0
  84. data/lib/facebooker/rails/facebook_url_rewriting.rb +52 -0
  85. data/lib/facebooker/rails/helpers/fb_connect.rb +90 -0
  86. data/lib/facebooker/rails/helpers.rb +772 -0
  87. data/lib/facebooker/rails/integration_session.rb +38 -0
  88. data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
  89. data/lib/facebooker/rails/publisher.rb +529 -0
  90. data/lib/facebooker/rails/routing.rb +49 -0
  91. data/lib/facebooker/rails/test_helpers.rb +68 -0
  92. data/lib/facebooker/rails/utilities.rb +22 -0
  93. data/lib/facebooker/server_cache.rb +24 -0
  94. data/lib/facebooker/service.rb +94 -0
  95. data/lib/facebooker/session.rb +596 -0
  96. data/lib/facebooker/version.rb +9 -0
  97. data/lib/facebooker.rb +181 -0
  98. data/lib/net/http_multipart_post.rb +123 -0
  99. data/lib/rack/facebook.rb +77 -0
  100. data/lib/tasks/facebooker.rake +18 -0
  101. data/lib/tasks/tunnel.rake +46 -0
  102. data/rails/init.rb +1 -0
  103. data/setup.rb +1585 -0
  104. data/templates/layout.erb +24 -0
  105. data/test/facebooker/adapters_test.rb +96 -0
  106. data/test/facebooker/admin_test.rb +102 -0
  107. data/test/facebooker/batch_request_test.rb +83 -0
  108. data/test/facebooker/data_test.rb +86 -0
  109. data/test/facebooker/logging_test.rb +43 -0
  110. data/test/facebooker/mobile_test.rb +45 -0
  111. data/test/facebooker/model_test.rb +123 -0
  112. data/test/facebooker/models/event_test.rb +15 -0
  113. data/test/facebooker/models/user_test.rb +331 -0
  114. data/test/facebooker/rails/publisher_test.rb +468 -0
  115. data/test/facebooker/rails_integration_test.rb +1330 -0
  116. data/test/facebooker/server_cache_test.rb +44 -0
  117. data/test/facebooker/session_test.rb +614 -0
  118. data/test/facebooker_test.rb +925 -0
  119. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  120. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  121. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  122. data/test/net/http_multipart_post_test.rb +52 -0
  123. data/test/rack/facebook_test.rb +62 -0
  124. data/test/rails_test_helper.rb +13 -0
  125. data/test/test_helper.rb +66 -0
  126. metadata +219 -0
data/lib/facebooker.rb ADDED
@@ -0,0 +1,181 @@
1
+ begin
2
+ unless Object.const_defined?("ActiveSupport") and ActiveSupport.const_defined?("JSON")
3
+ require 'json'
4
+ module Facebooker
5
+ def self.json_decode(str)
6
+ JSON.parse(str)
7
+ end
8
+ end
9
+ else
10
+ module Facebooker
11
+ def self.json_decode(str)
12
+ ActiveSupport::JSON.decode(str)
13
+ end
14
+ end
15
+ end
16
+ rescue
17
+ require 'json'
18
+ end
19
+ require 'zlib'
20
+ require 'digest/md5'
21
+
22
+
23
+
24
+ module Facebooker
25
+
26
+ class << self
27
+
28
+ def load_configuration(facebooker_yaml_file)
29
+ if File.exist?(facebooker_yaml_file)
30
+ if defined? RAILS_ENV
31
+ config = YAML.load_file(facebooker_yaml_file)[RAILS_ENV]
32
+ else
33
+ config = YAML.load_file(facebooker_yaml_file)
34
+ end
35
+ apply_configuration(config)
36
+ end
37
+ end
38
+
39
+ # Sets the Facebook environment based on a hash of options.
40
+ # By default the hash passed in is loaded from facebooker.yml, but it can also be passed in
41
+ # manually every request to run multiple Facebook apps off one Rails app.
42
+ def apply_configuration(config)
43
+ ENV['FACEBOOK_API_KEY'] = config['api_key']
44
+ ENV['FACEBOOK_SECRET_KEY'] = config['secret_key']
45
+ ENV['FACEBOOKER_RELATIVE_URL_ROOT'] = config['canvas_page_name']
46
+ ENV['FACEBOOKER_API'] = config['api']
47
+ if config.has_key?('set_asset_host_to_callback_url')
48
+ Facebooker.set_asset_host_to_callback_url = config['set_asset_host_to_callback_url']
49
+ end
50
+ if Object.const_defined?("ActionController") and Facebooker.set_asset_host_to_callback_url
51
+ ActionController::Base.asset_host = config['callback_url']
52
+ end
53
+ Facebooker.timeout = config['timeout']
54
+ @facebooker_configuration = config
55
+ end
56
+
57
+ def facebooker_config
58
+ @facebooker_configuration || {} # to prevent pretty_errors error if the config hasn't been set yet
59
+ end
60
+
61
+ def current_adapter=(adapter_class)
62
+ @current_adapter = adapter_class
63
+ end
64
+
65
+ def current_adapter
66
+ @current_adapter || Facebooker::AdapterBase.default_adapter
67
+ end
68
+
69
+ def load_adapter(params)
70
+ self.current_adapter = Facebooker::AdapterBase.load_adapter(params)
71
+ end
72
+
73
+ def facebook_path_prefix=(path)
74
+ current_adapter.facebook_path_prefix = path
75
+ end
76
+
77
+ # Default is canvas_page_name in yml file
78
+ def facebook_path_prefix
79
+ current_adapter.facebook_path_prefix
80
+ end
81
+
82
+ def is_for?(application_container)
83
+ current_adapter.is_for?(application_container)
84
+ end
85
+
86
+ def set_asset_host_to_callback_url=(val)
87
+ @set_asset_host_to_callback_url=val
88
+ end
89
+
90
+ def set_asset_host_to_callback_url
91
+ @set_asset_host_to_callback_url.nil? ? true : @set_asset_host_to_callback_url
92
+ end
93
+
94
+ def use_curl=(val)
95
+ @use_curl=val
96
+ end
97
+
98
+ def use_curl?
99
+ @use_curl
100
+ end
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
+ def path_prefix
116
+ @path_prefix
117
+ end
118
+
119
+
120
+ # Set the asset path to the canvas path for just this one request
121
+ # by definition, we will make this a canvas request
122
+ def with_asset_path_for_canvas
123
+ original_asset_host = ActionController::Base.asset_host
124
+ begin
125
+ ActionController::Base.asset_host = Facebooker.api_server_base_url
126
+ request_for_canvas(true) do
127
+ yield
128
+ end
129
+ ensure
130
+ ActionController::Base.asset_host = original_asset_host
131
+ end
132
+ end
133
+
134
+ # If this request is_canvas_request
135
+ # then use the application name as the url root
136
+ def request_for_canvas(is_canvas_request)
137
+ original_path_prefix = @path_prefix
138
+ begin
139
+ @path_prefix = facebook_path_prefix if is_canvas_request
140
+ yield
141
+ ensure
142
+ @path_prefix = original_path_prefix
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ require 'facebooker/batch_request'
149
+ require 'facebooker/feed'
150
+ require 'facebooker/logging'
151
+ require 'facebooker/model'
152
+ require 'facebooker/parser'
153
+ require 'facebooker/service'
154
+ require 'facebooker/server_cache'
155
+ require 'facebooker/data'
156
+ require 'facebooker/admin'
157
+ require 'facebooker/mobile'
158
+ require 'facebooker/session'
159
+ require 'facebooker/version'
160
+ require 'facebooker/models/location'
161
+ require 'facebooker/models/affiliation'
162
+ require 'facebooker/models/album'
163
+ require 'facebooker/models/education_info'
164
+ require 'facebooker/models/work_info'
165
+ require 'facebooker/models/event'
166
+ require 'facebooker/models/group'
167
+ require 'facebooker/models/notifications'
168
+ require 'facebooker/models/page'
169
+ require 'facebooker/models/photo'
170
+ require 'facebooker/models/cookie'
171
+ require 'facebooker/models/applicationproperties'
172
+ require 'facebooker/models/applicationrestrictions'
173
+ require 'facebooker/models/tag'
174
+ require 'facebooker/models/user'
175
+ require 'facebooker/models/info_item'
176
+ require 'facebooker/models/info_section'
177
+ require 'facebooker/models/friend_list'
178
+ require 'facebooker/models/video'
179
+ require 'facebooker/adapters/adapter_base'
180
+ require 'facebooker/adapters/facebook_adapter'
181
+ 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 |
23
+ egrep "tcp.*:#{@public_port}.*LISTEN" | wc`.to_i > 0
24
+ puts "Seems ok"
25
+ else
26
+ puts "Down"
27
+ end
28
+ end
29
+
30
+ task :config => :environment do
31
+ facebook_config = File.dirname(__FILE__) + '/../../../../../config/facebooker.yml'
32
+ FACEBOOKER = YAML.load_file(facebook_config)[RAILS_ENV]
33
+ @public_host_username = FACEBOOKER['tunnel']['public_host_username']
34
+ @public_host = FACEBOOKER['tunnel']['public_host']
35
+ @public_port = FACEBOOKER['tunnel']['public_port']
36
+ @local_port = FACEBOOKER['tunnel']['local_port']
37
+ @ssh_port = FACEBOOKER['tunnel']['ssh_port'] || 22
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 = "ssh -v -p #{@ssh_port} -nNT4 -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')