mini_fb 0.2.4 → 0.2.5
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/README.markdown +6 -2
- data/lib/mini_fb.rb +87 -31
- metadata +3 -3
data/README.markdown
CHANGED
@@ -67,8 +67,12 @@ Define an fb_connect method in your login/sessions controller like so:
|
|
67
67
|
@fb_session = cookies[FB_API_KEY + "_session_key"]
|
68
68
|
puts "uid=#{@fb_uid}"
|
69
69
|
puts "session=#{@fb_session}"
|
70
|
-
|
71
|
-
|
70
|
+
|
71
|
+
if MiniFB.verify_connect_signature(FB_API_KEY, FB_SECRET, cookies)
|
72
|
+
# And here you would create the user if it doesn't already exist, then redirect them to wherever you want.
|
73
|
+
else
|
74
|
+
# The cookies may have been modified as the signature does not match
|
75
|
+
end
|
72
76
|
|
73
77
|
end
|
74
78
|
|
data/lib/mini_fb.rb
CHANGED
@@ -114,7 +114,11 @@ module MiniFB
|
|
114
114
|
end
|
115
115
|
|
116
116
|
BAD_JSON_METHODS = ["users.getloggedinuser", "auth.promotesession", "users.hasapppermission",
|
117
|
-
"Auth.revokeExtendedPermission", "pages.isAdmin", "pages.isFan"
|
117
|
+
"Auth.revokeExtendedPermission", "pages.isAdmin", "pages.isFan",
|
118
|
+
"stream.publish",
|
119
|
+
"dashboard.addNews", "dashboard.addGlobalNews", "dashboard.publishActivity",
|
120
|
+
"dashboard.incrementcount", "dashboard.setcount"
|
121
|
+
].collect { |x| x.downcase }
|
118
122
|
|
119
123
|
# Call facebook server with a method request. Most keyword arguments
|
120
124
|
# are passed directly to the server with a few exceptions.
|
@@ -157,11 +161,7 @@ module MiniFB
|
|
157
161
|
|
158
162
|
file_name = kwargs.delete("filename")
|
159
163
|
|
160
|
-
|
161
|
-
arg_string = String.new
|
162
|
-
# todo: convert symbols to strings, symbols break the next line
|
163
|
-
kwargs.sort.each { |kv| arg_string << kv[0] << "=" << kv[1].to_s }
|
164
|
-
kwargs["sig"] = Digest::MD5.hexdigest( arg_string + secret.value.call )
|
164
|
+
kwargs["sig"] = signature_for(kwargs, secret.value.call)
|
165
165
|
|
166
166
|
fb_method = kwargs["method"].downcase
|
167
167
|
if fb_method == "photos.upload"
|
@@ -170,7 +170,7 @@ module MiniFB
|
|
170
170
|
else
|
171
171
|
|
172
172
|
begin
|
173
|
-
response = Net::HTTP.post_form( URI.parse(FB_URL), kwargs
|
173
|
+
response = Net::HTTP.post_form( URI.parse(FB_URL), post_params(kwargs))
|
174
174
|
rescue SocketError => err
|
175
175
|
# why are we catching this and throwing as different error? hmmm..
|
176
176
|
# raise IOError.new( "Cannot connect to the facebook server: " + err )
|
@@ -205,31 +205,31 @@ module MiniFB
|
|
205
205
|
return data
|
206
206
|
end
|
207
207
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
208
|
+
def MiniFB.post_upload(filename, kwargs)
|
209
|
+
content = File.open(filename, 'rb') { |f| f.read }
|
210
|
+
boundary = Digest::MD5.hexdigest(content)
|
211
|
+
header = {'Content-type' => "multipart/form-data, boundary=#{boundary}"}
|
212
|
+
|
213
|
+
# Build query
|
214
|
+
query = ''
|
215
|
+
kwargs.each { |a, v|
|
216
|
+
query <<
|
217
|
+
"--#{boundary}\r\n" <<
|
218
|
+
"Content-Disposition: form-data; name=\"#{a}\"\r\n\r\n" <<
|
219
|
+
"#{v}\r\n"
|
220
|
+
}
|
216
221
|
query <<
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
"--#{boundary}--"
|
229
|
-
|
230
|
-
# Call Facebook with POST multipart/form-data request
|
231
|
-
uri = URI.parse(FB_URL)
|
232
|
-
Net::HTTP.start(uri.host) {|http| http.post uri.path, query, header}
|
222
|
+
"--#{boundary}\r\n" <<
|
223
|
+
"Content-Disposition: form-data; filename=\"#{File.basename(filename)}\"\r\n" <<
|
224
|
+
"Content-Transfer-Encoding: binary\r\n" <<
|
225
|
+
"Content-Type: image/jpeg\r\n\r\n" <<
|
226
|
+
content <<
|
227
|
+
"\r\n" <<
|
228
|
+
"--#{boundary}--"
|
229
|
+
|
230
|
+
# Call Facebook with POST multipart/form-data request
|
231
|
+
uri = URI.parse(FB_URL)
|
232
|
+
Net::HTTP.start(uri.host) {|http| http.post uri.path, query, header}
|
233
233
|
end
|
234
234
|
|
235
235
|
# Returns true is signature is valid, false otherwise.
|
@@ -256,6 +256,36 @@ module MiniFB
|
|
256
256
|
return false
|
257
257
|
end
|
258
258
|
|
259
|
+
# Validates that the cookies sent by the user are those that were set by facebook. Since your
|
260
|
+
# secret is only known by you and facebook it is used to sign all of the cookies set.
|
261
|
+
#
|
262
|
+
# options:
|
263
|
+
# * api_key - the connect applications facebook API key
|
264
|
+
# * secret - the connect application secret
|
265
|
+
# * cookies - the cookies given by facebook - it is ok to just pass all of the cookies, the method will do the filtering for you.
|
266
|
+
def MiniFB.verify_connect_signature(api_key, secret, cookies)
|
267
|
+
signature = cookies[api_key]
|
268
|
+
return false if signature.nil?
|
269
|
+
|
270
|
+
unsigned = Hash.new
|
271
|
+
signed = Hash.new
|
272
|
+
|
273
|
+
cookies.each do |k, v|
|
274
|
+
if k =~ /^#{api_key}_(.*)/ then
|
275
|
+
signed[$1] = v
|
276
|
+
else
|
277
|
+
unsigned[k] = v
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
arg_string = String.new
|
282
|
+
signed.sort.each {|kv| arg_string << kv[0] << "=" << kv[1] }
|
283
|
+
if Digest::MD5.hexdigest(arg_string + secret) == signature
|
284
|
+
return true
|
285
|
+
end
|
286
|
+
return false
|
287
|
+
end
|
288
|
+
|
259
289
|
# Returns the login/add app url for your application.
|
260
290
|
#
|
261
291
|
# options:
|
@@ -320,4 +350,30 @@ module MiniFB
|
|
320
350
|
@value = Proc.new { value }
|
321
351
|
end
|
322
352
|
end
|
353
|
+
|
354
|
+
private
|
355
|
+
def self.post_params(params)
|
356
|
+
post_params = {}
|
357
|
+
params.each do |k, v|
|
358
|
+
k = k.to_s unless k.is_a?(String)
|
359
|
+
if Array === v || Hash === v
|
360
|
+
post_params[k] = JSON.dump(v)
|
361
|
+
else
|
362
|
+
post_params[k] = v
|
363
|
+
end
|
364
|
+
end
|
365
|
+
puts post_params.inspect
|
366
|
+
post_params
|
367
|
+
end
|
368
|
+
|
369
|
+
def self.signature_for(params, secret)
|
370
|
+
params.delete_if { |k, v| v.nil? }
|
371
|
+
raw_string = params.inject([]) do |collection, pair|
|
372
|
+
collection << pair.map { |x|
|
373
|
+
Array === x ? JSON.dump(x) : x
|
374
|
+
}.join("=")
|
375
|
+
collection
|
376
|
+
end.sort.join
|
377
|
+
Digest::MD5.hexdigest([raw_string, secret].join)
|
378
|
+
end
|
323
379
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 5
|
9
|
+
version: 0.2.5
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Travis Reeder
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-04-
|
18
|
+
date: 2010-04-20 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|