facebook-signed-request 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in facebook-signed-request.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,35 @@
1
+ ## Usage
2
+
3
+ ```ruby
4
+ require 'facebook-signed-request'
5
+ request = Facebook::SignedRequest.new( params[:signed_request], secret )
6
+
7
+ request.valid?
8
+ # => true / false
9
+
10
+ request.errors
11
+ # => [
12
+ # "Invalid Format. See http://developers.facebook.com/docs/authentication/signed_request/",
13
+ # "Invalid Base64 encoding for signature",
14
+ # "Invalid Base64 Encoding for data",
15
+ # "Invalid JSON object",
16
+ # "Invalid Algorithm. Expected: HMAC-SHA256",
17
+ # "Signatures do not match. #{expected} but was #{computed}"
18
+ #]
19
+
20
+ request.data
21
+ # => {
22
+ # "algorithm"=>"HMAC-SHA256",
23
+ # "expires"=>1308988800,
24
+ # "issued_at"=>1308985018,
25
+ # "oauth_token"=>"114998258593813|2.AQBAttRlLVnwqNPZ.3600.1308988800…",
26
+ # "user"=> {
27
+ # "country"=>"de",
28
+ # "locale"=>"en_US",
29
+ # "age"=>{"min"=>21}
30
+ # },
31
+ # "user_id"=>"100000656666199"
32
+ # }
33
+
34
+
35
+ ```
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "facebook-signed-request/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "facebook-signed-request"
7
+ s.version = Facebook::Signed::Request::VERSION
8
+ s.authors = ["hukl"]
9
+ s.email = ["contact@smyck.org"]
10
+ s.homepage = ""
11
+ s.summary = %q{Parses and validates Facebook signed requests}
12
+ s.description = %q{Parses and validates Facebook signed requests}
13
+
14
+ s.rubyforge_project = "facebook-signed-request"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ end
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'facebook-signed-request'))
2
+
3
+ require "facebook-signed-request/version"
4
+ require 'digest'
5
+ require 'base64'
6
+ require 'json'
7
+ require 'signed_request'
8
+
9
+ module Facebook
10
+
11
+
12
+
13
+ end
@@ -0,0 +1,79 @@
1
+ module Facebook
2
+ class SignedRequest
3
+ attr_reader :errors, :signature, :data
4
+
5
+ def initialize( request_data, secret )
6
+ @encoded_signature, @encoded_data = request_data.split(".", 2)
7
+
8
+ if @encoded_signature.nil? || @encoded_data.nil?
9
+ raise ArgumentError, "Invalid Format. See http://developers.facebook.com/docs/authentication/signed_request/"
10
+ end
11
+
12
+ @errors = []
13
+ @secret = secret
14
+
15
+ @signature = extract_request_signature
16
+ @payload = extract_request_payload
17
+ @data = parse_request_playload
18
+
19
+ validate_algorithm
20
+ validate_signature
21
+ end
22
+
23
+
24
+ def extract_request_signature
25
+ begin
26
+ return base64_url_decode(@encoded_signature).unpack('H*')[0]
27
+ rescue ArgumentError
28
+ @errors << "Invalid Base64 encoding for signature"
29
+ return nil
30
+ end
31
+ end
32
+
33
+ def extract_request_payload
34
+ begin
35
+ base64_url_decode(@encoded_data)
36
+ rescue ArgumentError
37
+ @errors << "Invalid Base64 Encoding for data"
38
+ return nil
39
+ end
40
+ end
41
+
42
+ def parse_request_playload
43
+ begin
44
+ return JSON.parse( @payload )
45
+ rescue
46
+ @errors << "Invalid JSON object"
47
+ return nil
48
+ end
49
+ end
50
+
51
+ def validate_algorithm
52
+ if @data.nil? || @data['algorithm'] != "HMAC-SHA256"
53
+ @errors << "Invalid Algorithm. Expected: HMAC-SHA256"
54
+ end
55
+ end
56
+
57
+ def validate_signature
58
+ digestor = Digest::HMAC.new( @secret, Digest::SHA256 )
59
+ computed_signature = digestor.hexdigest( @encoded_data )
60
+
61
+ if @signature != computed_signature
62
+ message = "Signatures do not match. " \
63
+ "Computed: #{computed_signature} but was #{@signature.inspect}"
64
+
65
+ @errors << message
66
+ end
67
+ end
68
+
69
+ def base64_url_decode( encoded_string )
70
+ encoded_string << '=' until ( encoded_string.length % 4 == 0 )
71
+ Base64.strict_decode64(encoded_string.gsub("-", "+").gsub("_", "/"))
72
+ end
73
+
74
+ def valid?
75
+ @errors.empty?
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,7 @@
1
+ module Facebook
2
+ module Signed
3
+ module Request
4
+ VERSION = "0.0.2"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,41 @@
1
+ $LOAD_PATH.unshift( File.dirname(__FILE__) )
2
+
3
+ require 'test_helper'
4
+
5
+ class SignedRequestTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @secret = "897a956a2f7eadcc5783a458fe3e7556"
9
+ @valid_request = "vl0p_bGyDeVZ2I21cJvLd5C9CwpMkU2mcp1eUGWdvWs.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEzMDg5ODg4MDAsImlzc3VlZF9hdCI6MTMwODk4NTAxOCwib2F1dGhfdG9rZW4iOiIxMTQ5NTIyOTg1OTM4MTN8Mi5BUUJBdHRSbExWbndxTlBaLjM2MDAuMTMwODk4ODgwMC4xLTEwMDAwMDY1NDM0MzE5OXxUNDl3M0Jxb1pVZWd5cHJ1NTFHcmE3MGhFRDgiLCJ1c2VyIjp7ImNvdW50cnkiOiJkZSIsImxvY2FsZSI6ImVuX1VTIiwiYWdlIjp7Im1pbiI6MjF9fSwidXNlcl9pZCI6IjEwMDAwMDY1NDM0MzE5OSJ9"
10
+ @invalid_request_1 = "l0p_bGyDeVZ2I21cJvLd5C9CwpMkU2mcp1eUGWdvWs.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEzMDg5ODg4MDAsImlzc3VlZF9hdCI6MTMwODk4NTAxOCwib2F1dGhfdG9rZW4iOiIxMTQ5NTIyOTg1OTM4MTN8Mi5BUUJBdHRSbExWbndxTlBaLjM2MDAuMTMwODk4ODgwMC4xLTEwMDAwMDY1NDM0MzE5OXxUNDl3M0Jxb1pVZWd5cHJ1NTFHcmE3MGhFRDgiLCJ1c2VyIjp7ImNvdW50cnkiOiJkZSIsImxvY2FsZSI6ImVuX1VTIiwiYWdlIjp7Im1pbiI6MjF9fSwidXNlcl9pZCI6IjEwMDAwMDY1NDM0MzE5OSJ9"
11
+ @invalid_request_2 = "vl0p_bGyDeVZ2I21cJvLd5C9CwpMkU2mcp1eUGWdvWs.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEzMDg5ODg4MDAsImlzc3VlZF9hdCI6MTMwODk4NTAxOCwib2F1dGhfdG9rZW4iOiIxMTQ5NTIyOTg1OTM4MTN8Mi5BUUJBdHRSbExWbndxTlBaLjM2MDAuMTMwODk4ODgwMC4xLTEwMDAwMDY1NDM0MzE5OXxUNDl3M0Jxb1pVZWd5cHJ1NTFHcmE3MGhFRDgiLCJ1c2VyIjp7ImNvdW50cnkiOiJkZSIsImxvY2FsZSI6ImVuX1VTIiwiYWdlIjp7Im1pbiI6MjF9fSwidXNlcl9pZCI6IjEwMDAwMDY1NDM0MzE5OSJ"
12
+
13
+ @foo = "Wkq_aQu7mLjm54kOMTXoQrfa-q0_FyHcwFIBeLXNMas.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEzMDkwODYwMDAsImlzc3VlZF9hdCI6MTMwOTA4MDg3MCwib2F1dGhfdG9rZW4iOiIxMTQ5NTIyOTg1OTM4MTN8Mi5BUUJCSXVhZlhlek5xdlR2LjM2MDAuMTMwOTA4NjAwMC4xLTEwMDAwMDY1NDM0MzE5OXxGN3RGZkQ4U2tkRmgydE9tMDAwOG5fRVBJcVkiLCJ1c2VyIjp7ImNvdW50cnkiOiJkZSIsImxvY2FsZSI6ImVuX1VTIiwiYWdlIjp7Im1pbiI6MjF9fSwidXNlcl9pZCI6IjEwMDAwMDY1NDM0MzE5OSJ9"
14
+ end
15
+
16
+ test "parsing a valid request" do
17
+ request = Facebook::SignedRequest.new( @valid_request, @secret )
18
+ assert request.valid?, "Request should be valid"
19
+ assert request.errors == [], "Request should contain no errors"
20
+ end
21
+
22
+ test "parsing a request with invalid signature" do
23
+ request = Facebook::SignedRequest.new( @invalid_request_1, @secret )
24
+ assert_equal false, request.valid?
25
+ assert_equal 2, request.errors.length
26
+ end
27
+
28
+ test "parsing a request with invalid payload" do
29
+ request = Facebook::SignedRequest.new( @invalid_request_2, @secret )
30
+ assert_equal false, request.valid?
31
+ assert_equal 4, request.errors.length
32
+ end
33
+
34
+ test "re-encoding of payload" do
35
+ request = Facebook::SignedRequest.new( @foo, @secret )
36
+
37
+ puts Base64.encode64 request.data.to_json.to_s
38
+
39
+
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ $LOAD_PATH.unshift( File.join( File.dirname(__FILE__), "..", "lib") )
2
+
3
+ require 'test/unit'
4
+ require 'facebook-signed-request'
5
+
6
+ class Test::Unit::TestCase
7
+
8
+ unless defined?(Spec)
9
+ # test "verify something" do
10
+ # ...
11
+ # end
12
+ def self.test(name, &block)
13
+ test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
14
+ defined = instance_method(test_name) rescue false
15
+ raise "#{test_name} is already defined in #{self}" if defined
16
+ if block_given?
17
+ define_method(test_name, &block)
18
+ else
19
+ define_method(test_name) do
20
+ flunk "No implementation provided for #{name}"
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: facebook-signed-request
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - hukl
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-06-26 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+ description: Parses and validates Facebook signed requests
16
+ email:
17
+ - contact@smyck.org
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - README.markdown
25
+ - Rakefile
26
+ - facebook-signed-request.gemspec
27
+ - lib/facebook-signed-request.rb
28
+ - lib/facebook-signed-request/signed_request.rb
29
+ - lib/facebook-signed-request/version.rb
30
+ - test/signed_request_test.rb
31
+ - test/test_helper.rb
32
+ has_rdoc: true
33
+ homepage: ''
34
+ licenses: []
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ requirements: []
52
+ rubyforge_project: facebook-signed-request
53
+ rubygems_version: 1.6.2
54
+ signing_key:
55
+ specification_version: 3
56
+ summary: Parses and validates Facebook signed requests
57
+ test_files:
58
+ - test/signed_request_test.rb
59
+ - test/test_helper.rb