mini_fb 0.1.8 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/mini_fb.rb +277 -276
  2. data/test/mini_fb_tests.rb +1 -1
  3. metadata +3 -2
data/lib/mini_fb.rb CHANGED
@@ -1,276 +1,277 @@
1
- module MiniFB
2
- require 'digest/md5'
3
- require 'erb'
4
- require 'json/pure'
5
-
6
- # Global constants
7
- FB_URL = "http://api.facebook.com/restserver.php"
8
- FB_API_VERSION = "1.0"
9
-
10
- @@logging = false
11
-
12
- def enable_logging
13
- @@logging = true
14
- end
15
-
16
- def disable_logging
17
- @@logging = false
18
- end
19
-
20
- class FaceBookError < StandardError
21
- # Error that happens during a facebook call.
22
- def initialize( error_code, error_msg )
23
- super("Facebook error #{error_code}: #{error_msg}" )
24
- end
25
- end
26
-
27
- class Session
28
- attr_accessor :api_key, :secret_key, :session_key, :uid
29
-
30
-
31
- def initialize(api_key, secret_key, session_key, uid)
32
- @api_key = api_key
33
- @secret_key = FaceBookSecret.new secret_key
34
- @session_key = session_key
35
- @uid = uid
36
- end
37
-
38
- # returns current user
39
- def user
40
- return @user unless @user.nil?
41
- @user = User.new(MiniFB.call(@api_key, @secret_key, "Users.getInfo", "session_key"=>@session_key, "uids"=>@uid, "fields"=>User.all_fields)[0], self)
42
- @user
43
- end
44
-
45
- def photos
46
- Photos.new(self)
47
- end
48
-
49
-
50
- def call(method, params={})
51
- return MiniFB.call(api_key, secret_key, method, params.update("session_key"=>session_key))
52
- end
53
-
54
-
55
- end
56
- class User
57
- FIELDS = [:uid, :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]
58
- STANDARD_FIELDS = [:uid, :first_name, :last_name, :name, :timezone, :birthday, :sex, :affiliations, :locale, :profile_url, :proxied_email]
59
-
60
- def self.all_fields
61
- FIELDS.join(",")
62
- end
63
-
64
- def self.standard_fields
65
- STANDARD_FIELDS.join(",")
66
- end
67
-
68
- def initialize(fb_hash, session)
69
- @fb_hash = fb_hash
70
- @session = session
71
- end
72
-
73
- def [](key)
74
- @fb_hash[key]
75
- end
76
-
77
- def uid
78
- return self["uid"]
79
- end
80
-
81
- def profile_photos
82
- @session.photos.get("uid"=>uid, "aid"=>profile_pic_album_id)
83
- end
84
-
85
- def profile_pic_album_id
86
- merge_aid(-3, uid)
87
- end
88
-
89
- def merge_aid(aid, uid)
90
- uid = uid.to_i
91
- ret = (uid << 32) + (aid & 0xFFFFFFFF)
92
- # puts 'merge_aid=' + ret.inspect
93
- return ret
94
- end
95
- end
96
-
97
- class Photos
98
-
99
- def initialize(session)
100
- @session = session
101
- end
102
-
103
- def get(params)
104
- pids = params["pids"]
105
- if !pids.nil? && pids.is_a?(Array)
106
- pids = pids.join(",")
107
- params["pids"] = pids
108
- end
109
- @session.call("photos.get", params)
110
- end
111
- end
112
-
113
- # Call facebook server with a method request. Most keyword arguments
114
- # are passed directly to the server with a few exceptions.
115
- # The 'sig' value will always be computed automatically.
116
- # The 'v' version will be supplied automatically if needed.
117
- # The 'call_id' defaults to True, which will generate a valid
118
- # number. Otherwise it should be a valid number or False to disable.
119
-
120
- # The default return is a parsed json object.
121
- # Unless the 'format' and/or 'callback' arguments are given,
122
- # in which case the raw text of the reply is returned. The string
123
- # will always be returned, even during errors.
124
-
125
- # If an error occurs, a FacebookError exception will be raised
126
- # with the proper code and message.
127
-
128
- # The secret argument should be an instance of FacebookSecret
129
- # to hide value from simple introspection.
130
- def MiniFB.call( api_key, secret, method, kwargs )
131
-
132
- puts 'kwargs=' + kwargs.inspect
133
-
134
- if secret.is_a? String
135
- secret = FaceBookSecret.new(secret)
136
- end
137
-
138
- # Prepare arguments for call
139
- call_id = kwargs.fetch("call_id", true)
140
- if call_id == true then
141
- kwargs["call_id"] = Time.now.tv_sec.to_s
142
- else
143
- kwargs.delete("call_id")
144
- end
145
-
146
- custom_format = kwargs.include?("format") or kwargs.include?("callback")
147
- kwargs["format"] ||= "JSON"
148
- kwargs["v"] ||= FB_API_VERSION
149
- kwargs["api_key"]||= api_key
150
- kwargs["method"] ||= method
151
-
152
- # Hash with secret
153
- arg_string = String.new
154
- # todo: convert symbols to strings, symbols break the next line
155
- kwargs.sort.each { |kv| arg_string << kv[0] << "=" << kv[1].to_s }
156
- kwargs["sig"] = Digest::MD5.hexdigest( arg_string + secret.value.call )
157
-
158
- # Call website with POST request
159
- begin
160
- response = Net::HTTP.post_form( URI.parse(FB_URL), kwargs )
161
- rescue SocketError => err
162
- raise IOError.new( "Cannot connect to the facebook server: " + err )
163
- end
164
-
165
- # Handle response
166
- return response.body if custom_format
167
-
168
- fb_method = kwargs["method"]
169
- body = response.body
170
-
171
- begin
172
- data = JSON.parse( body )
173
- puts 'response=' + data.inspect if @@logging
174
- if data.include?( "error_msg" ) then
175
- raise FaceBookError.new( data["error_code"] || 1, data["error_msg"] )
176
- end
177
-
178
- rescue JSON::ParserError => ex
179
- if fb_method == "users.getLoggedInUser" # Little hack because this response isn't valid JSON
180
- return body
181
- else
182
- raise ex
183
- end
184
- end
185
- return data
186
- end
187
-
188
- # Returns true is signature is valid, false otherwise.
189
- def MiniFB.verify_signature( secret, arguments )
190
- signature = arguments.delete( "fb_sig" )
191
- return false if signature.nil?
192
-
193
- unsigned = Hash.new
194
- signed = Hash.new
195
-
196
- arguments.each do |k, v|
197
- if k =~ /^fb_sig_(.*)/ then
198
- signed[$1] = v
199
- else
200
- unsigned[k] = v
201
- end
202
- end
203
-
204
- arg_string = String.new
205
- signed.sort.each { |kv| arg_string << kv[0] << "=" << kv[1] }
206
- if Digest::MD5.hexdigest( arg_string + secret ) == signature
207
- return true
208
- end
209
- return false
210
- end
211
-
212
- # Returns the login/add app url for your application.
213
- #
214
- # options:
215
- # - :next => a relative next page to go to. relative to your facebook connect url or if :canvas is true, then relative to facebook app url
216
- # - :canvas => true/false - to say whether this is a canvas app or not
217
- def self.login_url(api_key, options={})
218
- login_url = "http://api.facebook.com/login.php?api_key=#{api_key}"
219
- login_url << "&next=#{options[:next]}" if options[:next]
220
- login_url << "&canvas" if options[:canvas]
221
- login_url
222
- end
223
-
224
- # This function expects arguments as a hash, so
225
- # it is agnostic to different POST handling variants in ruby.
226
- #
227
- # Validate the arguments received from facebook. This is usually
228
- # sent for the iframe in Facebook's canvas. It is not necessary
229
- # to use this on the auth_token and uid passed to callbacks like
230
- # post-add and post-remove.
231
- #
232
- # The arguments must be a mapping of to string keys and values
233
- # or a string of http request data.
234
- #
235
- # If the data is invalid or not signed properly, an empty
236
- # dictionary is returned.
237
- #
238
- # The secret argument should be an instance of FacebookSecret
239
- # to hide value from simple introspection.
240
- #
241
- # DEPRECATED, use verify_signature instead
242
- def MiniFB.validate( secret, arguments )
243
-
244
- signature = arguments.delete( "fb_sig" )
245
- return arguments if signature.nil?
246
-
247
- unsigned = Hash.new
248
- signed = Hash.new
249
-
250
- arguments.each do |k, v|
251
- if k =~ /^fb_sig_(.*)/ then
252
- signed[$1] = v
253
- else
254
- unsigned[k] = v
255
- end
256
- end
257
-
258
- arg_string = String.new
259
- signed.sort.each { |kv| arg_string << kv[0] << "=" << kv[1] }
260
- if Digest::MD5.hexdigest( arg_string + secret ) != signature
261
- unsigned # Hash is incorrect, return only unsigned fields.
262
- else
263
- unsigned.merge signed
264
- end
265
- end
266
-
267
- class FaceBookSecret
268
- # Simple container that stores a secret value.
269
- # Proc cannot be dumped or introspected by normal tools.
270
- attr_reader :value
271
-
272
- def initialize( value )
273
- @value = Proc.new { value }
274
- end
275
- end
276
- end
1
+ require 'digest/md5'
2
+ require 'erb'
3
+ require 'json' unless defined? JSON
4
+
5
+ module MiniFB
6
+
7
+ # Global constants
8
+ FB_URL = "http://api.facebook.com/restserver.php"
9
+ FB_API_VERSION = "1.0"
10
+
11
+ @@logging = false
12
+
13
+ def enable_logging
14
+ @@logging = true
15
+ end
16
+
17
+ def disable_logging
18
+ @@logging = false
19
+ end
20
+
21
+ class FaceBookError < StandardError
22
+ # Error that happens during a facebook call.
23
+ def initialize( error_code, error_msg )
24
+ super("Facebook error #{error_code}: #{error_msg}" )
25
+ end
26
+ end
27
+
28
+ class Session
29
+ attr_accessor :api_key, :secret_key, :session_key, :uid
30
+
31
+
32
+ def initialize(api_key, secret_key, session_key, uid)
33
+ @api_key = api_key
34
+ @secret_key = FaceBookSecret.new secret_key
35
+ @session_key = session_key
36
+ @uid = uid
37
+ end
38
+
39
+ # returns current user
40
+ def user
41
+ return @user unless @user.nil?
42
+ @user = User.new(MiniFB.call(@api_key, @secret_key, "Users.getInfo", "session_key"=>@session_key, "uids"=>@uid, "fields"=>User.all_fields)[0], self)
43
+ @user
44
+ end
45
+
46
+ def photos
47
+ Photos.new(self)
48
+ end
49
+
50
+
51
+ def call(method, params={})
52
+ return MiniFB.call(api_key, secret_key, method, params.update("session_key"=>session_key))
53
+ end
54
+
55
+
56
+ end
57
+ class User
58
+ FIELDS = [:uid, :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]
59
+ STANDARD_FIELDS = [:uid, :first_name, :last_name, :name, :timezone, :birthday, :sex, :affiliations, :locale, :profile_url, :proxied_email]
60
+
61
+ def self.all_fields
62
+ FIELDS.join(",")
63
+ end
64
+
65
+ def self.standard_fields
66
+ STANDARD_FIELDS.join(",")
67
+ end
68
+
69
+ def initialize(fb_hash, session)
70
+ @fb_hash = fb_hash
71
+ @session = session
72
+ end
73
+
74
+ def [](key)
75
+ @fb_hash[key]
76
+ end
77
+
78
+ def uid
79
+ return self["uid"]
80
+ end
81
+
82
+ def profile_photos
83
+ @session.photos.get("uid"=>uid, "aid"=>profile_pic_album_id)
84
+ end
85
+
86
+ def profile_pic_album_id
87
+ merge_aid(-3, uid)
88
+ end
89
+
90
+ def merge_aid(aid, uid)
91
+ uid = uid.to_i
92
+ ret = (uid << 32) + (aid & 0xFFFFFFFF)
93
+ # puts 'merge_aid=' + ret.inspect
94
+ return ret
95
+ end
96
+ end
97
+
98
+ class Photos
99
+
100
+ def initialize(session)
101
+ @session = session
102
+ end
103
+
104
+ def get(params)
105
+ pids = params["pids"]
106
+ if !pids.nil? && pids.is_a?(Array)
107
+ pids = pids.join(",")
108
+ params["pids"] = pids
109
+ end
110
+ @session.call("photos.get", params)
111
+ end
112
+ end
113
+
114
+ # Call facebook server with a method request. Most keyword arguments
115
+ # are passed directly to the server with a few exceptions.
116
+ # The 'sig' value will always be computed automatically.
117
+ # The 'v' version will be supplied automatically if needed.
118
+ # The 'call_id' defaults to True, which will generate a valid
119
+ # number. Otherwise it should be a valid number or False to disable.
120
+
121
+ # The default return is a parsed json object.
122
+ # Unless the 'format' and/or 'callback' arguments are given,
123
+ # in which case the raw text of the reply is returned. The string
124
+ # will always be returned, even during errors.
125
+
126
+ # If an error occurs, a FacebookError exception will be raised
127
+ # with the proper code and message.
128
+
129
+ # The secret argument should be an instance of FacebookSecret
130
+ # to hide value from simple introspection.
131
+ def MiniFB.call( api_key, secret, method, kwargs )
132
+
133
+ puts 'kwargs=' + kwargs.inspect
134
+
135
+ if secret.is_a? String
136
+ secret = FaceBookSecret.new(secret)
137
+ end
138
+
139
+ # Prepare arguments for call
140
+ call_id = kwargs.fetch("call_id", true)
141
+ if call_id == true then
142
+ kwargs["call_id"] = Time.now.tv_sec.to_s
143
+ else
144
+ kwargs.delete("call_id")
145
+ end
146
+
147
+ custom_format = kwargs.include?("format") or kwargs.include?("callback")
148
+ kwargs["format"] ||= "JSON"
149
+ kwargs["v"] ||= FB_API_VERSION
150
+ kwargs["api_key"]||= api_key
151
+ kwargs["method"] ||= method
152
+
153
+ # Hash with secret
154
+ arg_string = String.new
155
+ # todo: convert symbols to strings, symbols break the next line
156
+ kwargs.sort.each { |kv| arg_string << kv[0] << "=" << kv[1].to_s }
157
+ kwargs["sig"] = Digest::MD5.hexdigest( arg_string + secret.value.call )
158
+
159
+ # Call website with POST request
160
+ begin
161
+ response = Net::HTTP.post_form( URI.parse(FB_URL), kwargs )
162
+ rescue SocketError => err
163
+ raise IOError.new( "Cannot connect to the facebook server: " + err )
164
+ end
165
+
166
+ # Handle response
167
+ return response.body if custom_format
168
+
169
+ fb_method = kwargs["method"]
170
+ body = response.body
171
+
172
+ begin
173
+ data = JSON.parse( body )
174
+ puts 'response=' + data.inspect if @@logging
175
+ if data.include?( "error_msg" ) then
176
+ raise FaceBookError.new( data["error_code"] || 1, data["error_msg"] )
177
+ end
178
+
179
+ rescue JSON::ParserError => ex
180
+ if fb_method == "users.getLoggedInUser" # Little hack because this response isn't valid JSON
181
+ return body
182
+ else
183
+ raise ex
184
+ end
185
+ end
186
+ return data
187
+ end
188
+
189
+ # Returns true is signature is valid, false otherwise.
190
+ def MiniFB.verify_signature( secret, arguments )
191
+ signature = arguments.delete( "fb_sig" )
192
+ return false if signature.nil?
193
+
194
+ unsigned = Hash.new
195
+ signed = Hash.new
196
+
197
+ arguments.each do |k, v|
198
+ if k =~ /^fb_sig_(.*)/ then
199
+ signed[$1] = v
200
+ else
201
+ unsigned[k] = v
202
+ end
203
+ end
204
+
205
+ arg_string = String.new
206
+ signed.sort.each { |kv| arg_string << kv[0] << "=" << kv[1] }
207
+ if Digest::MD5.hexdigest( arg_string + secret ) == signature
208
+ return true
209
+ end
210
+ return false
211
+ end
212
+
213
+ # Returns the login/add app url for your application.
214
+ #
215
+ # options:
216
+ # - :next => a relative next page to go to. relative to your facebook connect url or if :canvas is true, then relative to facebook app url
217
+ # - :canvas => true/false - to say whether this is a canvas app or not
218
+ def self.login_url(api_key, options={})
219
+ login_url = "http://api.facebook.com/login.php?api_key=#{api_key}"
220
+ login_url << "&next=#{options[:next]}" if options[:next]
221
+ login_url << "&canvas" if options[:canvas]
222
+ login_url
223
+ end
224
+
225
+ # This function expects arguments as a hash, so
226
+ # it is agnostic to different POST handling variants in ruby.
227
+ #
228
+ # Validate the arguments received from facebook. This is usually
229
+ # sent for the iframe in Facebook's canvas. It is not necessary
230
+ # to use this on the auth_token and uid passed to callbacks like
231
+ # post-add and post-remove.
232
+ #
233
+ # The arguments must be a mapping of to string keys and values
234
+ # or a string of http request data.
235
+ #
236
+ # If the data is invalid or not signed properly, an empty
237
+ # dictionary is returned.
238
+ #
239
+ # The secret argument should be an instance of FacebookSecret
240
+ # to hide value from simple introspection.
241
+ #
242
+ # DEPRECATED, use verify_signature instead
243
+ def MiniFB.validate( secret, arguments )
244
+
245
+ signature = arguments.delete( "fb_sig" )
246
+ return arguments if signature.nil?
247
+
248
+ unsigned = Hash.new
249
+ signed = Hash.new
250
+
251
+ arguments.each do |k, v|
252
+ if k =~ /^fb_sig_(.*)/ then
253
+ signed[$1] = v
254
+ else
255
+ unsigned[k] = v
256
+ end
257
+ end
258
+
259
+ arg_string = String.new
260
+ signed.sort.each { |kv| arg_string << kv[0] << "=" << kv[1] }
261
+ if Digest::MD5.hexdigest( arg_string + secret ) != signature
262
+ unsigned # Hash is incorrect, return only unsigned fields.
263
+ else
264
+ unsigned.merge signed
265
+ end
266
+ end
267
+
268
+ class FaceBookSecret
269
+ # Simple container that stores a secret value.
270
+ # Proc cannot be dumped or introspected by normal tools.
271
+ attr_reader :value
272
+
273
+ def initialize( value )
274
+ @value = Proc.new { value }
275
+ end
276
+ end
277
+ end
@@ -1,8 +1,8 @@
1
1
  require 'test/unit'
2
2
  class MiniFBTests < Test::Unit::TestCase
3
3
 
4
- def setup
5
4
 
5
+ def setup
6
6
  end
7
7
 
8
8
  def teardown
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_fb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Travis Reeder
8
+ - Aaron Hurley
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
12
 
12
- date: 2009-11-13 00:00:00 -08:00
13
+ date: 2009-12-03 00:00:00 -08:00
13
14
  default_executable:
14
15
  dependencies: []
15
16