koala 1.0.0.beta2 → 1.0.0.beta2.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -19,6 +19,7 @@ Internal improvements:
19
19
  -- Beta 2: photo and file uploads now accept symbols as well as strings overall
20
20
  -- Beta 2: APIError is now < StandardError, not Exception
21
21
  -- Beta 2: Added KoalaError for non-API errors
22
+ -- Beta 3: Updated parse_signed_request to match Facebook's current implementation (thanks, imajes!)
22
23
  Test improvements:
23
24
  -- Expanded HTTP service tests (added Typhoeus test suite and additional Net::HTTP test cases)
24
25
  -- Live tests now verify that the access token has the necessary permissions before starting
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'rake'
4
4
  require 'echoe'
5
5
 
6
6
  # gem management
7
- Echoe.new('koala', '1.0.0.beta2') do |p|
7
+ Echoe.new('koala', '1.0.0.beta2.1') do |p|
8
8
  p.summary = "A lightweight, flexible library for Facebook with support for the Graph API, the old REST API, realtime updates, and OAuth validation."
9
9
  p.description = "Koala is a lightweight, flexible Ruby SDK for Facebook. It allows read/write access to the social graph via the Graph API and the older REST API, as well as support for realtime updates and OAuth and Facebook Connect authentication. Koala is fully tested and supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services."
10
10
  p.url = "http://github.com/arsduo/koala"
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{koala}
5
- s.version = "1.0.0.beta2"
5
+ s.version = "1.0.0.beta2.1"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional"]
9
- s.date = %q{2011-03-10}
9
+ s.date = %q{2011-04-06}
10
10
  s.description = %q{Koala is a lightweight, flexible Ruby SDK for Facebook. It allows read/write access to the social graph via the Graph API and the older REST API, as well as support for realtime updates and OAuth and Facebook Connect authentication. Koala is fully tested and supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services.}
11
11
  s.email = %q{alex@alexkoppel.com}
12
12
  s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "lib/koala.rb", "lib/koala/graph_api.rb", "lib/koala/http_services.rb", "lib/koala/realtime_updates.rb", "lib/koala/rest_api.rb", "lib/koala/test_users.rb", "lib/koala/uploadable_io.rb"]
@@ -211,38 +211,24 @@ module Koala
211
211
  string = info["access_token"]
212
212
  end
213
213
  end
214
-
215
- # provided directly by Facebook
216
- # see https://github.com/facebook/crypto-request-examples/blob/master/sample.rb
217
- # and http://developers.facebook.com/docs/authentication/canvas/encryption_proposal
218
- def parse_signed_request(input, max_age = 3600)
214
+
215
+ # Originally provided directly by Facebook, however this has changed
216
+ # as their concept of crypto changed. For historic purposes, this is their proposal:
217
+ # https://developers.facebook.com/docs/authentication/canvas/encryption_proposal/
218
+ # Currently see https://github.com/facebook/php-sdk/blob/master/src/facebook.php#L758
219
+ # for a more accurate reference implementation strategy.
220
+ def parse_signed_request(input)
219
221
  encoded_sig, encoded_envelope = input.split('.', 2)
222
+ signature = base64_url_decode(encoded_sig).unpack("H*").first
220
223
  envelope = JSON.parse(base64_url_decode(encoded_envelope))
221
- algorithm = envelope['algorithm']
222
-
223
- raise 'Invalid request. (Unsupported algorithm.)' \
224
- if algorithm != 'AES-256-CBC HMAC-SHA256' && algorithm != 'HMAC-SHA256'
225
-
226
- raise 'Invalid request. (Too old.)' \
227
- if algorithm == "AES-256-CBC HMAC-SHA256" && envelope['issued_at'].to_i < Time.now.to_i - max_age
228
-
229
- raise 'Invalid request. (Invalid signature.)' \
230
- if base64_url_decode(encoded_sig) !=
231
- OpenSSL::HMAC.hexdigest(
232
- 'sha256', @app_secret, encoded_envelope).split.pack('H*')
233
-
234
- # for requests that are signed, but not encrypted, we're done
235
- return envelope if algorithm == 'HMAC-SHA256'
236
-
237
- # otherwise, decrypt the payload
238
- cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
239
- cipher.decrypt
240
- cipher.key = @app_secret
241
- cipher.iv = base64_url_decode(envelope['iv'])
242
- cipher.padding = 0
243
- decrypted_data = cipher.update(base64_url_decode(envelope['payload']))
244
- decrypted_data << cipher.final
245
- return JSON.parse(decrypted_data.strip)
224
+
225
+ raise "SignedRequest: Unsupported algorithm #{envelope['algorithm']}" if envelope['algorithm'] != 'HMAC-SHA256'
226
+
227
+ # now see if the signature is valid (digest, key, data)
228
+ hmac = OpenSSL::HMAC.hexdigest('sha256', @app_secret, encoded_envelope.tr("-_", "+/"))
229
+ raise 'SignedRequest: Invalid signature' if (signature != hmac)
230
+
231
+ return envelope
246
232
  end
247
233
 
248
234
  # from session keys
@@ -309,7 +295,7 @@ module Koala
309
295
  # directly from https://github.com/facebook/crypto-request-examples/raw/master/sample.rb
310
296
  def base64_url_decode(str)
311
297
  str += '=' * (4 - str.length.modulo(4))
312
- Base64.decode64(str.gsub('-', '+').gsub('_', '/'))
298
+ Base64.decode64(str.tr('-_', '+/'))
313
299
  end
314
300
  end
315
301
  end
@@ -57,12 +57,6 @@ module Koala
57
57
  http = Net::HTTP.new(server(options), private_request ? 443 : nil)
58
58
  http.use_ssl = true if private_request
59
59
 
60
- # we turn off certificate validation to avoid the
61
- # "warning: peer certificate won't be verified in this SSL session" warning
62
- # not sure if this is the right way to handle it
63
- # see http://redcorundum.blogspot.com/2008/03/ssl-certificates-and-nethttps.html
64
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
65
-
66
60
  result = http.start do |http|
67
61
  response, body = if verb == "post"
68
62
  if params_require_multipart? args
@@ -5,18 +5,18 @@
5
5
 
6
6
  # You must supply this value yourself to test the GraphAPI class.
7
7
  # Your OAuth token should have publish_stream, read_stream, and user_photos permissions.
8
- oauth_token:
8
+ oauth_token: 119908831367602|2.SzVOt20se6d7VnLzsG3USg__.3600.1302102000-2905623|Qxhc8NPxIQFKuNOaL1XdYNcztAM
9
9
 
10
10
  # for testing the OAuth class
11
11
  # baseline app
12
12
  oauth_test_data:
13
13
  # You must supply this value yourself, since they will expire.
14
- code:
14
+ code: 2.SzVOt20se6d7VnLzsG3USg__.3600.1302102000-2905623|Z5x3PcJgROjfj6DOwVQpb714nkQ
15
15
  # easiest way to get session keys: use multiple test accounts with the Javascript login at http://oauth.twoalex.com
16
- session_key:
16
+ session_key: 2.SzVOt20se6d7VnLzsG3USg__.3600.1302102000-2905623
17
17
  multiple_session_keys:
18
- -
19
- -
18
+ - 2.SzVOt20se6d7VnLzsG3USg__.3600.1302102000-2905623
19
+ - 2.SzVOt20se6d7VnLzsG3USg__.3600.1302102000-2905623
20
20
 
21
21
  # These values will work out of the box
22
22
  app_id: 119908831367602
@@ -35,23 +35,21 @@ oauth_test_data:
35
35
  # note: I've revoked the offline access for security reasons, so you can't make calls against this :)
36
36
  fbs_119908831367602: '"access_token=119908831367602|08170230801eb225068e7a70-2905623|Q3LDCYYF8CX9cstxnZLsxiR0nwg.&expires=0&secret=78abaee300b392e275072a9f2727d436&session_key=08170230801eb225068e7a70-2905623&sig=423b8aa4b6fa1f9a571955f8e929d567&uid=2905623"'
37
37
 
38
- # These values will work out of the box
39
- # They're from Facebook's example at http://developers.facebook.com/docs/authentication/canvas
38
+ # These values from the OAuth Playground (see above) will work out of the box
40
39
  # You can update this to live data if desired
41
40
  # request_secret is optional and will fall back to the secret above if absent
42
- request_secret: "secret"
43
- signed_request: "vlXgu64BQGFSQrY0ZcJBZASMvYvTHu9GQ0YM9rjPSso.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsIjAiOiJwYXlsb2FkIn0"
44
- signed_request_result:
45
- "0": payload
46
- algorithm: HMAC-SHA256
47
- # signed params
48
- # examples from http://developers.facebook.com/docs/authentication/canvas/encryption_proposal
49
- signed_params: t63pZQ4Q3ZTHJt0hOsKrY2pb28xRlduW0pg4lL_Zhl4.eyJhbGdvcml0aG0iOiJBRVMtMjU2LUNCQyBITUFDLVNIQTI1NiIsImlzc3VlZF9hdCI6MTI4NzYwMTk4OCwiaXYiOiJmRExKQ1cteWlYbXVOYTI0ZVNhckpnIiwicGF5bG9hZCI6IllHeW00cG9Rbk1UckVnaUFPa0ZUVkk4NWxsNVJ1VWlFbC1JZ3FmeFRPVEhRTkl2VlZJOFk4a1Z1T29lS2FXT2Vhc3NXRlRFdjBRZ183d0NDQkVlbjdsVUJCemxGSjFWNjNISjNBZjBTSW5nY3hXVEo3TDZZTGF0TW13WGdEQXZXbjVQc2ZxeldrNG1sOWg5RExuWXB0V0htREdMNmlCaU9oTjdXeUk3cDZvRXBWcmlGdUp3X2NoTG9QYjhhM3ZHRG5vVzhlMlN4eDA2QTJ4MnhraWFwdmcifQ
50
- signed_params_secret: 13750c9911fec5865d01f3bd00bdf4db
41
+ signed_params: "zWRm0gd5oHW_jzXP_WA9CirO7c5CLHotn-SKRqH2NmU.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEzMDE5MjIwMDAsImlzc3VlZF9hdCI6MTMwMTkxNzI5OSwib2F1dGhfdG9rZW4iOiIxMTk5MDg4MzEzNjc2MDJ8Mi56VkZfNk5yTUVMSHVKYTRnSVU5dEt3X18uMzYwMC4xMzAxOTIyMDAwLTI5MDU2MjN8emdxUHNyMkJHOUxvT0s5a2VrR2dSVVJaeDBrIiwidXNlciI6eyJjb3VudHJ5IjoiZGUiLCJsb2NhbGUiOiJkZV9ERSIsImFnZSI6eyJtaW4iOjIxfX0sInVzZXJfaWQiOiIyOTA1NjIzIn0"
51
42
  signed_params_result:
52
- access_token: "101244219942650|2.wdrSr7KyE_VwQ0fjwOfW9A__.3600.1287608400-499091902|XzxMQd-_4tjlC2VEgide4rmg6LI"
53
- expires_in: 6412
54
- user_id: "499091902"
43
+ expires: 1301922000
44
+ algorithm: HMAC-SHA256
45
+ user_id: "2905623"
46
+ oauth_token: 119908831367602|2.zVF_6NrMELHuJa4gIU9tKw__.3600.1301922000-2905623|zgqPsr2BG9LoOK9kekGgRURZx0k
47
+ user:
48
+ country: de
49
+ locale: de_DE
50
+ age:
51
+ min: 21
52
+ issued_at: 1301917299
55
53
 
56
54
  subscription_test_data:
57
55
  subscription_path: http://oauth.twoalex.com/subscriptions
@@ -22,7 +22,7 @@ shared_examples_for "Koala GraphAPI without an access token" do
22
22
  # these are not strictly necessary as the other put methods resolve to put_object, but are here for completeness
23
23
  it "should not be able to post to a feed" do
24
24
  (lambda do
25
- attachment = {:name => "Context Optional", :link => "http://www.contextoptional.com/"}
25
+ attachment = {:name => "OAuth Playground", :link => "http://www.oauth.twoalex.com/"}
26
26
  @result = @api.put_wall_post("Hello, world", attachment, "contextoptional")
27
27
  end).should raise_error(Koala::Facebook::APIError)
28
28
  puts "Error! Object #{@result.inspect} somehow put onto Context Optional's wall!" if @result
@@ -55,7 +55,7 @@ shared_examples_for "Koala GraphAPI with an access token" do
55
55
  end
56
56
 
57
57
  it "should be able to post a message with an attachment to a feed" do
58
- result = @api.put_wall_post("Hello, world, from the test suite again!", {:name => "Context Optional", :link => "http://www.contextoptional.com/"})
58
+ result = @api.put_wall_post("Hello, world, from the test suite again!", {:name => "OAuth Playground", :link => "http://oauth.twoalex.com/"})
59
59
  @temporary_object_id = result["id"]
60
60
  @temporary_object_id.should_not be_nil
61
61
  end
@@ -93,7 +93,7 @@ shared_examples_for "Koala GraphAPI with an access token" do
93
93
  end
94
94
 
95
95
  it "should be able to verify a message with an attachment posted to a feed" do
96
- attachment = {"name" => "Context Optional", "link" => "http://www.contextoptional.com/"}
96
+ attachment = {"name" => "OAuth Playground", "link" => "http://oauth.twoalex.com/"}
97
97
  result = @api.put_wall_post("Hello, world, from the test suite again!", attachment)
98
98
  @temporary_object_id = result["id"]
99
99
  get_result = @api.get_object(@temporary_object_id)
@@ -138,8 +138,8 @@ class NetHTTPServiceTests < Test::Unit::TestCase
138
138
  Bear.make_request('anything', {}, 'anything', :rest_api => true)
139
139
  end
140
140
 
141
- it "should turn off vertificate validaiton warnings" do
142
- @http_mock.should_receive('verify_mode=').with(OpenSSL::SSL::VERIFY_NONE)
141
+ it "no longer turns off vertificate validaiton warnings" do
142
+ @http_mock.should_not_receive('verify_mode=')
143
143
 
144
144
  Bear.make_request('anything', {}, 'anything')
145
145
  end
@@ -10,14 +10,7 @@ class FacebookOAuthTests < Test::Unit::TestCase
10
10
  @raw_token_string = @oauth_data["raw_token_string"]
11
11
  @raw_offline_access_token_string = @oauth_data["raw_offline_access_token_string"]
12
12
 
13
- # per Facebook's example:
14
- # http://developers.facebook.com/docs/authentication/canvas
15
- # this allows us to use Facebook's example data while running the other live data
16
- @request_secret = @oauth_data["request_secret"] || @secret
17
- @signed_request = @oauth_data["signed_request"]
18
- @signed_request_result = @oauth_data["signed_request_result"]
19
13
  # for signed requests (http://developers.facebook.com/docs/authentication/canvas/encryption_proposal)
20
- @signed_params_secret = @oauth_data["signed_params_secret"] || @secret
21
14
  @signed_params = @oauth_data["signed_params"]
22
15
  @signed_params_result = @oauth_data["signed_params_result"]
23
16
 
@@ -354,12 +347,6 @@ class FacebookOAuthTests < Test::Unit::TestCase
354
347
  end
355
348
 
356
349
  describe "for parsing signed requests" do
357
- before :each do
358
- # you can test against live data by updating the YML, or you can use the default data
359
- # which tests against Facebook's example on http://developers.facebook.com/docs/authentication/canvas
360
- @oauth = Koala::Facebook::OAuth.new(@app_id, @request_secret || @app_secret)
361
- end
362
-
363
350
  # the signed request code comes directly from Facebook
364
351
  # so we only need to test at a high level that it works
365
352
  # signed params refers to http://developers.facebook.com/docs/authentication/canvas
@@ -374,34 +361,10 @@ class FacebookOAuthTests < Test::Unit::TestCase
374
361
  lambda { @oauth.parse_signed_request(@signed_request) }.should raise_error
375
362
  end
376
363
 
377
- describe "for signed params" do
378
- it "should work" do
379
- @oauth.parse_signed_request(@signed_request).should == @signed_request_result
380
- end
364
+ it "properly parses requests" do
365
+ @oauth = Koala::Facebook::OAuth.new(@app_id, @secret || @app_secret)
366
+ @oauth.parse_signed_request(@signed_params).should == @signed_params_result
381
367
  end
382
-
383
- describe "for signed requests" do
384
- it "should work" do
385
- @oauth = Koala::Facebook::OAuth.new(@app_id, @signed_params_secret || @app_secret)
386
- @oauth.parse_signed_request(@signed_params).should == @signed_params_result
387
- end
388
-
389
- it "should throw an error if the params are too old" do
390
- @time.stub!(:to_i).and_return(1287601988 + 4000)
391
- @oauth = Koala::Facebook::OAuth.new(@app_id, @signed_params_secret || @app_secret)
392
-
393
- lambda { @oauth.parse_signed_request(@signed_params) }.should raise_error
394
- end
395
-
396
- it "should let you specify the max age for a request" do
397
- @time.stub!(:to_i).and_return(1287601988 + 4000)
398
- @oauth = Koala::Facebook::OAuth.new(@app_id, @signed_params_secret || @app_secret)
399
-
400
- lambda { @oauth.parse_signed_request(@signed_params, 4001) }.should_not raise_error
401
- end
402
-
403
- end
404
-
405
368
  end
406
369
 
407
370
  end # describe
@@ -10,10 +10,10 @@ else
10
10
  # Ruby 1.8.x
11
11
  require 'test/unit'
12
12
  require 'rubygems'
13
-
14
- require 'spec/test/unit'
15
13
  end
16
14
 
15
+ require 'yaml'
16
+
17
17
  # load the libraries
18
18
  require 'koala'
19
19
 
@@ -83,7 +83,7 @@ graph_api:
83
83
  message=Hello, world, from the test suite delete method!:
84
84
  post:
85
85
  with_token: '{"id": "FEED_ITEM_DELETE"}'
86
- link=http://www.contextoptional.com/&message=Hello, world, from the test suite again!&name=Context Optional:
86
+ link=http://oauth.twoalex.com/&message=Hello, world, from the test suite again!&name=OAuth Playground:
87
87
  post:
88
88
  with_token: '{"id": "FEED_ITEM_CONTEXT"}'
89
89
  /me/photos:
@@ -238,7 +238,7 @@ graph_api:
238
238
  no_args:
239
239
  <<: *item_deleted
240
240
  get:
241
- with_token: '{"link":"http://www.contextoptional.com/", "name": "Context Optional"}'
241
+ with_token: '{"link":"http://oauth.twoalex.com/", "name": "OAuth Playground"}'
242
242
 
243
243
  /FEED_ITEM_CATS:
244
244
  no_args:
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: koala
3
3
  version: !ruby/object:Gem::Version
4
- hash: 62196359
4
+ hash: 124392909
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 1
@@ -9,7 +9,8 @@ version: !ruby/object:Gem::Version
9
9
  - 0
10
10
  - beta
11
11
  - 2
12
- version: 1.0.0.beta2
12
+ - 1
13
+ version: 1.0.0.beta2.1
13
14
  platform: ruby
14
15
  authors:
15
16
  - Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional
@@ -17,7 +18,7 @@ autorequire:
17
18
  bindir: bin
18
19
  cert_chain: []
19
20
 
20
- date: 2011-03-10 00:00:00 +01:00
21
+ date: 2011-04-06 00:00:00 +02:00
21
22
  default_executable:
22
23
  dependencies:
23
24
  - !ruby/object:Gem::Dependency